【问题标题】:What would be the best way to write a query to produce a table given the following data?给定以下数据,编写查询以生成表的最佳方法是什么?
【发布时间】:2019-11-19 15:54:16
【问题描述】:

我有一个包含以下数据的表:

  ADD_Col         Data      OrderId     Output     NEW_ADD        Col1       Col2
  -----          ------   -------      ----->       -------     --------   -------
     AD*A*1      A       96                           A           1          2
     AD*A*1      B       95                           B           1          1
     AD*A*1      C       94                           C           0.8        1
     AD*A*1      D       93                           D           5          2
     AD*A*2      1       92 
     AD*A*2      1       91
     AD*A*2      0.8     90
     AD*A*2      5       89
     AD*A*3      2       88
     AD*A*3      1       87
     AD*A*3      1       86
     AD*A*3      2       85

这些数据都在同一个表中,我需要将每个字母链接到每个因素。我正在考虑做一个ROW_NUMBER() 并根据各自的行号加入,并为我的字母分配相同的数字或DENSERANK。实现这一目标的最佳方法是什么?如果可以,请提供查询示例,非常感谢。

【问题讨论】:

  • 什么定义了数据的顺序?我看不到任何东西可以使用ORDER BY 保留该订单;让你的要求变得不可能。
  • 抱歉,您说得对,我可以使用的另一列是订单 ID。添加到示例。
  • 我强烈建议不要对列名使用保留关键字。
  • 这只是一个例子,并没有在我的代码中使用。我在提供的示例中对此进行了更改。

标签: sql sql-server join row-number


【解决方案1】:

看来您需要做的是在这里规范化您的数据。这里我使用PARSENAME 获取“列号”,然后使用ROW_NUMBER 对组中的相关行进行编号。最后,我使用交叉表来透视数据:

WITH CTE AS(
    SELECT V.[Key],
           V.data,
           V.[Order],
           PARSENAME(REPLACE(V.[Key],'*','.'),1) AS ColNo,
           ROW_NUMBER() OVER (PARTITION BY V.[Key] ORDER BY V.[Order] DESC) AS RN
    FROM (VALUES('AD*A*1','A',96),       
                ('AD*A*1','B',95),       
                ('AD*A*1','C',94),       
                ('AD*A*1','D',93),       
                ('AD*A*2','1',92),
                ('AD*A*2','1',91),
                ('AD*A*2','0.8',90),
                ('AD*A*2','5',89),
                ('AD*A*3','2',88),
                ('AD*A*3','1',87),
                ('AD*A*3','1',86),
                ('AD*A*3','2',85))V([Key],[data],[Order]))
SELECT MAX(CASE C.ColNo WHEN '1' THEN C.[data] END) AS New_ADD,
       MAX(CASE C.ColNo WHEN '2' THEN C.[data] END) AS Col1,
       MAX(CASE C.ColNo WHEN '3' THEN C.[data] END) AS Col2
FROM CTE C
GROUP BY C.RN;

【讨论】:

  • 感谢您的回答 Larnu 我正在消化这一点。这是我需要的,但让我问你一些事情。如果我们没有列号,您的方法是什么?另外,回到您之前所说的关于缺少订单的内容,为什么没有订单列就无法完成这项任务?仍在学习 SQL 的基本知识,因此感谢您的耐心等待。
  • 因为如果你没有什么可订购的,那么现在5 的值与D 相关,你怎么办?如果没有一个专栏来确定这一点,你就不可能“嫁给”他们,@ErickRamirez。
  • 这个数字是任意的,@ErickRamirez。例如,它可以是一封信;它只是一个标识它属于哪一列的值。
【解决方案2】:

对于您的示例数据,这将起作用:

with cte as (
  select *, 
    row_number() over (partition by [key] order by [OrderId desc]) rn,
    dense_rank() over (order by [key]) rk
  from tablename
)  
select t1.data, 
  max(case when t2.rk = 2 then t2.data end) col1,
  max(case when t2.rk = 3 then t2.data end) col2
from (select * from cte where rk = 1) t1
inner join (select * from cte where rk in (2, 3)) t2
on t2.rn = t1.rn
group by t1.data 

请参阅demo
结果:

> data | col1 | col2
> :--- | :--- | :---
> A    | 1    | 2   
> B    | 1    | 1   
> C    | 0.8  | 1   
> D    | 5    | 2   

【讨论】:

  • 我喜欢这个答案,因为它完成了任务并且易于阅读和理解。
【解决方案3】:
select t1.Data "Key"
       , t2.Data "Col1"
       , t3.Data "Col2" 
from ((SELECT Data, 
              row_number() over (order by Key_C) rn
       from my_table 
       where Key_C = 'AD*A*1') t1
       left join
      (SELECT Data,
              row_number() over (order by Key_C) rn
       from my_table
       where Key_C = 'AD*A*2') t2
       on t1.rn = t2.rn
       left join
      (SELECT Data,
              row_number() over (order by Key_C) rn
       from my_table
       where Key_C = 'AD*A*3') t3
       on t2.rn = t3.rn);

这里是DEMO

【讨论】:

  • my_table 的 3 次扫描在这里似乎有点矫枉过正。
【解决方案4】:
DROP TABLE IF EXISTS #RawData
SELECT 
    [ADD_Col]
    ,[Data]
    ,[OrderId]
    ,REPLACE([ADD_Col], 'AD*A*', '') AS [Level]
    ,DENSE_RANK() OVER (PARTITION BY [ADD_Col] ORDER BY [OrderId] DESC) AS [Grouping]
INTO
    #RawData
FROM 
    [SourceTable]

SELECT
    rd.[Data]
    ,rdc1.[Data] AS [Col1]
    ,rdc2.[Data] AS [Col2]
FROM
    #RawData AS rd
    LEFT OUTER JOIN #RawData AS rdc1
        ON rdc1.[Level] = 2
        AND rd.[Grouping] = rdc1.[Grouping]
    LEFT OUTER JOIN #RawData AS rdc2
        ON rdc2.[Level] = 3
        AND rd.[Grouping] = rdc2.[Grouping]
WHERE
    rd.[Level] = 1

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-12-01
    • 1970-01-01
    • 2016-02-23
    • 1970-01-01
    • 1970-01-01
    • 2023-03-18
    相关资源
    最近更新 更多