1

在编写此查询时需要大家的帮助。

Field 1  
========
Hello
Man
Lady

我需要结果:

F1             F2             F3
=================================
Hello          Null           Null
Man            Null           Null
Lady           Null           Null
Hello          Man            Null
Hello          Lady           Null
Man            Lady           Null
Hello          Man            Lady
==================================  
4

2 回答 2

6

由于没有其他列可以确保 Man 排在 Lady 之前,这很有效。所以这里的一些排列与你的输出相反

添加另一个值,但它会变得复杂

DECLARE @t TABLE (SomeCol varchar(30));

INSERT @t VALUES ('Hello'), ('Man'), ('Lady');

SELECT *
FROM
    (
    SELECT DISTINCT
        t1.SomeCol AS F1,
        CASE WHEN t2.SomeCol = t1.SomeCol THEN NULL ELSE t2.SomeCol END AS F2,
        CASE WHEN t2.SomeCol = t1.SomeCol OR t3.SomeCol = t1.SomeCol OR t3.SomeCol = t2.SomeCol THEN NULL ELSE t3.SomeCol END AS F3
        --,
        --CASE WHEN NULLIF(t2.SomeCol, t1.SomeCol) IS NULL THEN NULL ELSE NULLIF(NULLIF(t3.SomeCol, t2.SomeCol), NULLIF(t3.SomeCol, t1.SomeCol)) END AS F3
    FROM
        @t t1
        JOIN
        @t t2 ON t1.SomeCol <= t2.SomeCol
        JOIN
        @t t3 ON t2.SomeCol <= t3.SomeCol
    ) X
ORDER BY
    F3, F2, F1;

与其他一些排序列

DECLARE @t TABLE (ID int IDENTITY(1,1), SomeCol varchar(30));

INSERT @t VALUES ('Hello'), ('Man'), ('Lady');

SELECT *
FROM 
    (
    SELECT DISTINCT
        t1.SomeCol AS F1,
        CASE WHEN t2.SomeCol = t1.SomeCol THEN NULL ELSE t2.SomeCol END AS F2,
        CASE WHEN t2.SomeCol = t1.SomeCol OR t3.SomeCol = t1.SomeCol OR t3.SomeCol = t2.SomeCol THEN NULL ELSE t3.SomeCol END AS F3
    FROM
        @t t1
        JOIN
        @t t2 ON t1.ID <= t2.ID
        JOIN
        @t t3 ON t2.ID <= t3.ID
    ) X
ORDER BY
    F3, F2, F1;
于 2013-06-13T14:57:54.880 回答
2

我写了一个函数,它返回列表中所有项目的组合。你需要在这个函数上做一些工作才能得到“作为数据集”的结果(所以它不会只返回组合——作为列表项——而是你想看到的)。


USE [MYDB_NAME_HERE]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE FUNCTION [dbo].[ItemCombinations]    (
   @strSep char(1) = ';',       --REQUIRED, the character to split the @List string on
   @myItemList varchar(max),    --REQUIRED, list of items which should be combined
   @minUse int,         --combine at least this number of items from the list
   @maxUse int          --combine at most this number of items from the list
                                            )
RETURNS @combos TABLE (myCols varchar(max))
AS
BEGIN
    IF (@myItemList = '')
        RETURN
    DECLARE @tmpRetVal TABLE    (
                                    unID tinyint IDENTITY(1,1) PRIMARY KEY NONCLUSTERED,
                                    cols varchar(500),
                                    bitV AS CONVERT (integer, POWER(2, unID - 1)) PERSISTED UNIQUE CLUSTERED
                                )
    DECLARE @tmpRes TABLE       (
                                    colcount int NULL,
                                    cols varchar(max)
                                )

    INSERT INTO @tmpRetVal (cols)
        SELECT * FROM dbo.StrSplit (';',@myItemList) AS cols

    DECLARE @max integer = POWER (2, (SELECT COUNT(*) FROM @tmpRetVal AS tRET)) - 1;

    INSERT INTO @tmpRes (cols)
        SELECT combination = STUFF ((   SELECT @strSep + tRET.cols 
                                        FROM @tmpRetVal AS tRET
                                        WHERE NUM.Number & tRET.bitV = tRET.bitV
                                        ORDER BY tRET.bitV
                                        FOR XML PATH (''),
                                        TYPE).value('(./text())[1]', 'varchar(8000)'), 1, 1, '')
        FROM [dbo].[Numbers] AS NUM
        WHERE NUM.Number BETWEEN 1 AND @max;

    UPDATE @tmpRes SET colcount = (LEN(cols) - LEN(REPLACE(cols, @strSep, '')) + 1)

    DELETE FROM @tmpRes WHERE (colcount  @maxUse)

    INSERT INTO @combos (myCols)
        SELECT cols FROM @tmpRes
    RETURN
END


与(例如)这个人在这里立即进行测试:


SELECT * FROM [dbo].[ItemCombinations] (';','Lady;Man;Hello',1,3)
GO

将给出这个结果集:同样,您可以修改函数以返回数据集/数据表而不是项目列表,然后您就在那里。 编辑:忘记添加我的 StrSplit 函数
Lady
Man
Lady;Man
Foo
Lady;Foo
Man;Foo
Lady;Man;Foo






USE [MYDB_NAME_HERE]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
-- =============================================
-- FUNCTIONALITY: splits a [delimeter] separated string into list of items: 1 item == 1 record
--                e.g. "that;wasn't;chicken" delimetered by ";" will turn into a recordset of 3 records
-- =============================================
CREATE FUNCTION [dbo].[StrSplit]    (
@strSep char(1) = ';',      --REQUIRED, the character to split the @List string on
@myList varchar(max)--REQUIRED, the list to split apart
                    )
RETURNS @sItems TABLE (txItem varchar(10))
AS
BEGIN
    IF @myList IS NULL RETURN

DECLARE @iStart int
DECLARE @iPos int

IF SUBSTRING(@myList,1,1) = @strSep
    BEGIN
        SET @iStart = 2
        INSERT INTO @sItems
        VALUES
            (NULL)
    END
ELSE
    SET @iStart = 1
WHILE 1=1
BEGIN
    SET @iPos = CHARINDEX( @strSep, @myList, @iStart )
    IF @iPos = 0 SET @iPos = LEN( @myList )+1
    IF @iPos - @iStart > 0
        INSERT INTO @sItems
        VALUES
            (SUBSTRING( @myList, @iStart, @iPos-@iStart ))
    ELSE
        INSERT INTO @sItems
        VALUES
            (NULL)
    SET @iStart = @iPos+1
    IF @iStart > len( @myList ) 
        BREAK
END
RETURN

END


(使用复杂的函数来展开列表,而不是因为 SQL Server 与交叉调用-SP 与函数相关的限制而更简单的 SP)

于 2013-06-13T14:58:12.677 回答