【问题标题】:Pivot and filter枢轴和过滤器
【发布时间】:2012-05-23 12:56:24
【问题描述】:

我正在尝试创建一个动态 Pivot,但似乎无法使其正常工作。

表:

SELECT [CaseID], [ClientID]
from [RegData]

目前返回:

CaseID--|ClientID| RecID
------------------------
7845107 |115172  |410
7845107 |164570  |1197
7845107 |115655  |416
7845107 |154244  |425
7856846 |116684  |151
7856846 |112354  |445
7455444 |115172  |492
7455444 |164570  |518
7455444 |115655  |1297
7455444 |154244  |681

我需要它像这样返回:

CaseID--|Val1----|Val2----|Val3----|Val4----|
7845107 |115172  |164570  |115655  |154244  |
7856846 |116684  |112354  |        |        |
7455444 |115172  |164570  |115655  |154244  |

然后,我需要找到 CaseID 不同但 VAL1、VAL2、VAL3 等相同的实例。

CaseID--|Val1----|Val2----|Val3----|Val4----|
7845107 |115172  |164570  |115655  |154244  |
7455444 |115172  |164570  |115655  |154244  |

【问题讨论】:

  • 您如何确定 164570 是 Val2 而 115655 是 Val3? SQL Server 需要数据支持的某种方式(或可以引入查询的确定性方式)来支持该排序。您在这里的查询没有 ORDER BY,所以我怀疑您假设因为这是这次返回数据的方式,所以这就是它始终返回的顺序?这是一个常见的误解,但它仍然是一个误解。您是否有其他列可以帮助确定您的预期顺序(例如身份或日期/时间列)?
  • 嗨亚伦,非常公平。为了尽量减少混乱,我省略了“RecID”列,它实际上是每一行的唯一标识符。
  • 那么在您上面的示例中,这些行是按 RecID 排序的吗?通常我们更喜欢完整的信息......我们是聪明的人,混乱通常不会让我们慢下来太多。所以我建议您至少将 RecID 值添加到第一组。
  • 他们在第一个表中没有排序。我猜如果需要,列标题可能是 ClientID。也就是说,在返回的示例中,Value1 的列标题可能是“115172”,所有具有“115172”的行都将具有值“115172”。不确定如何找到 CaseID 不同且列标题相同的实例...
  • 好的。同样,RecID 和 ClientID 都没有规定顺序。您看到的顺序是任意的(因为您没有 order by),并且在您下次运行查询时它可能会完全改变(当您告诉引擎您不关心时 SQL 选择的顺序可能会根据许多因素而改变)。您想要开发这个基于您当前在这些任意结果中看到的匹配值的数据透视查询,而 SQL Server 不能以这种方式工作。除非你能解释为什么 154244 的两个实例都属于 Value4 列的合乎逻辑的原因,否则恐怕你不走运......

标签: sql-server tsql sql-server-2005 pivot


【解决方案1】:

这里有很多免责声明。依靠您只关心所有 4 个值都很重要的情况。如果其中一个案例的第 5 个客户不匹配,或者有两个以上的案例具有相同的一组客户,我没有测试会发生什么。它适用于您提供的示例数据,但您希望在每个 Value1 / Value2 列等中看到的值的显示顺序与您的示例输出不同。

DECLARE @x TABLE(CaseID INT, ClientID INT);

INSERT @x SELECT 7845107,115172 UNION ALL SELECT 7845107,164570
UNION ALL SELECT 7845107,115655 UNION ALL SELECT 7845107,154244
UNION ALL SELECT 7856846,116684 UNION ALL SELECT 7856846,112354
UNION ALL SELECT 7455444,115172 UNION ALL SELECT 7455444,164570
UNION ALL SELECT 7455444,115655 UNION ALL SELECT 7455444,154244;

;WITH x AS
(
  SELECT CaseID, ClientID, rn = ROW_NUMBER() OVER 
  (PARTITION BY CaseID ORDER BY ClientID) 
  FROM @x
),
y AS 
(
    SELECT x.CaseID, x.ClientID, x.rn
    FROM x INNER JOIN x AS x2
    ON x.CaseID <> x2.CaseID
    AND x.ClientID = x2.ClientID
    AND x.rn = x2.rn
)
SELECT CaseID, 
    Value1 = MAX(CASE WHEN rn = 1 THEN ClientID END),
    Value2 = MAX(CASE WHEN rn = 2 THEN ClientID END),
    Value3 = MAX(CASE WHEN rn = 3 THEN ClientID END),
    Value4 = MAX(CASE WHEN rn = 4 THEN ClientID END)
FROM y
GROUP BY CaseID;

结果:

CaseID   Value1  Value2  Value3  Value4
-------  ------  ------  ------  ------
7455444  115172  115655  154244  164570
7845107  115172  115655  154244  164570

【讨论】:

  • 似乎无法编译。有问题,在 INSERT @x VALUES (7845107,115172), (7845107,164570) 之后,
  • @Rya INSERT 每行单独然后通过执行 INSERT INTO @x (val1, val2) 并为每个值对重复 INSERT INTO。如果出现错误,似乎 sql 2005 无法一次插入多个值。
  • 抱歉@Rya,我错过了 SQL Server 2005 标签(该语法在现代版本的 SQL Server 上有效)。当然,您也可以只针对您的表而不是针对@x 尝试查询 - 我只是将其包括在内以证明它的工作方式与您所要求的类似。
【解决方案2】:

这就是我想出的。效率不是很高,但是很管用……

我创建了一个表。我碰巧知道他们在一组中不超过 9 个相同的案例,因此是 Val9。

DECLARE 
    @totalRecords int,
    @counter int,
    @QueryCaseID int,
    @QueryClientID int,
    @queryVal1 int,
    @queryVal2 int,
    @queryVal3 int,
    @queryVal4 int,
    @queryVal5 int,
    @queryVal6 int,
    @queryVal7 int,
    @queryVal8 int,
    @queryVal9 int

Set @totalRecords = (Select count(*) from RegData) +1 
Set @counter = 1

-- Get the rows in the table and put them into the 'RegData_reformat' table
While @counter < @totalRecords
    Begin

        -- get the CASEID to cross query to reformatted table
        SET @QueryCaseID = (Select CaseID from RegData where RecID = @counter)

        -- get the ClientId to cross query to reformatted table
        SET @QueryClientID = (Select ClientID from RegData where RecID = @counter)



        -- assign the columns to variables
        SET @queryVal1 = (Select Val1 from RegData_reformat where CaseID = @QueryCaseID)
        SET @queryVal2 = (Select Val2 from RegData_reformat where CaseID = @QueryCaseID)
        SET @queryVal3 = (Select Val3 from RegData_reformat where CaseID = @QueryCaseID)
        SET @queryVal4 = (Select Val4 from RegData_reformat where CaseID = @QueryCaseID)
        SET @queryVal5 = (Select Val5 from RegData_reformat where CaseID = @QueryCaseID)
        SET @queryVal6 = (Select Val6 from RegData_reformat where CaseID = @QueryCaseID)
        SET @queryVal7 = (Select Val7 from RegData_reformat where CaseID = @QueryCaseID)
        SET @queryVal8 = (Select Val8 from RegData_reformat where CaseID = @QueryCaseID)
        SET @queryVal9 = (Select Val9 from RegData_reformat where CaseID = @QueryCaseID)


        --determine which column to insert the data into


--  Insert the data into the formatted table

        IF @queryVal1 IS NULL
            BEGIN
                UPDATE [4DISCSReporting].[dbo].[RegData_reformat]
                SET [Val1] = @QueryClientID
                WHERE CaseID = @QueryCaseID
            END

    -- Column 2 test
        else IF @queryVal2 IS NULL
            BEGIN
                UPDATE [4DISCSReporting].[dbo].[RegData_reformat]
                SET [Val2] = @QueryClientID
                WHERE CaseID = @QueryCaseID
            END

    -- Column 3 test
        else IF @queryVal3 IS NULL
            BEGIN
                UPDATE [4DISCSReporting].[dbo].[RegData_reformat]
                SET [Val3] = @QueryClientID
                WHERE CaseID = @QueryCaseID
            END

    -- Column 4 test
        else IF @queryVal4 IS NULL
            BEGIN
                UPDATE [4DISCSReporting].[dbo].[RegData_reformat]
                SET [Val4] = @QueryClientID
                WHERE CaseID = @QueryCaseID
            END

    -- Column 5 test            
        else IF @queryVal5 IS NULL
            BEGIN

                UPDATE [4DISCSReporting].[dbo].[RegData_reformat]
                SET [Val5] = @QueryClientID
                WHERE CaseID = @QueryCaseID
            END

    -- Column 6 test
        else IF @queryVal6 IS NULL
            BEGIN

                UPDATE [4DISCSReporting].[dbo].[RegData_reformat]
                SET [Val6] = @QueryClientID
                WHERE CaseID = @QueryCaseID
            END

    -- Column 7 test
        else IF @queryVal7 IS NULL
            BEGIN

                UPDATE [4DISCSReporting].[dbo].[RegData_reformat]
                SET [Val7] = @QueryClientID
                WHERE CaseID = @QueryCaseID
            END

    -- Column 8 test
        else IF @queryVal8 IS NULL
            BEGIN

                UPDATE [4DISCSReporting].[dbo].[RegData_reformat]
                SET [Val8] = @QueryClientID
                WHERE CaseID = @QueryCaseID
            END

    -- Column 9 test
        else IF @queryVal9 IS NULL
            BEGIN

                UPDATE [4DISCSReporting].[dbo].[RegData_reformat]
                SET [Val9] = @QueryClientID
                WHERE CaseID = @QueryCaseID
            END



        ELSE
            BEGIN
                print 'Ran out of columns to enter data into'
                Select 'FATAL ERROR: ran out of columns to enter data into' as Error
            END



    set @counter = @counter +1  


    END

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-08-26
    • 2021-06-01
    • 2015-07-31
    • 2021-10-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多