查询一行,该行返回数据所在的列及其之前的所有列

时间:2019-05-03 02:35:31

标签: sql

嗨,我有一张桌子,当我查询一行时,我想知道特定数据出现在哪一列

                        TABLE
            | A1 | A2 | A3 | A4 | A5 | ID |
              QA    W    E    R    T    1
               Y    U    I   QA    O    2
               G    H   QA    U    T    3 

例如,当我查询ID = 1的表时,我想知道发生在哪一列QA及其之前的所有列的情况下,单行中的数据将永远不会出现两次。

示例

         Select * from table where ID=1
                | A1 | ID |
                  QA    1

         Select * from table where ID=2
           | A1 | A2 | A3 | A4 | ID |
             Y     U    I   QA   2

我正在考虑为每一列使用5次case语句,但是我不知道如何在case语句内的THEN子句之后创建一个不同的select语句。

    select case when A3 = 'QA' then select A1,A2,A3 from table where ID = 1)

? 谢谢

1 个答案:

答案 0 :(得分:1)

有两种选择。本质上,您需要取消透视列,以便获取值。而且,您可以使用CTE过滤所需结果的结果。您可以使用T-SQL的UNPIVOTCROSS APPLY(这可能会更快,并且可能会提供更简洁的查询计划)。

提供您的数据:

交叉应用示例:

; WITH myList AS (
  SELECT t1.ID, ca.ColName, ca.Val
      , ROW_NUMBER() OVER (PARTITION BY t1.ID ORDER BY ca.ColName) AS rn
  FROM t1
  CROSS APPLY (
      VALUES 
        ('Row_1', A1)
      , ('Row_2', A2)
      , ('Row_3', A3)
      , ('Row_4', A4)
      , ('Row_5', A5)
    ) ca(ColName, Val)
  WHERE t1.ID = 2
)
, myPicks AS (
    SELECT ID, ColName, Val, rn
    FROM myList
    WHERE Val = 'QA'
)
SELECT l.ID, l.ColName, l.Val
FROM myList l
INNER JOIN myPicks p ON l.ID = p.ID
    AND l.rn <= p.rn

UNPIVOT示例:

; WITH myList AS (
  SELECT unpiv.ID, unpiv.ColName, unpiv.Val
    , ROW_NUMBER() OVER (PARTITION BY unpiv.ID ORDER BY unpiv.ColName) AS rn
  FROM t1
  UNPIVOT 
  (
      Val 
      FOR ColName IN ( A1, A5, A3, A2, A4 )
  ) unpiv
  WHERE unpiv.ID = 2
)
, myPicks AS (
    SELECT ID, ColName, Val, rn
    FROM myList
    WHERE Val = 'QA'

)
SELECT l.ID, l.ColName, l.Val
FROM myList l
INNER JOIN myPicks p ON l.ID = p.ID
    AND l.rn <= p.rn

...会给你...

ID  ColName Val
2   A1      Y
2   A2      U
2   A3      I
2   A4      QA

这会将您的数据放入行中,这可能更易于使用编程语言进行操作,从而重新定义所需的方式。我不太确定您打算如何使用此代码或C#将如何使用它。这可能会改变实现它的最佳方式。

无论如何,不​​一定要保证SQL中的列列表会按特定顺序返回,并且如前所述,不应依赖列顺序。 PIVOT / UNPIVOT的当前行为当前将按照您在IN子句中放置的顺序对“列”进行排序,但这不是文档记录的行为,可以在任何更新时更改。在SQL中最可靠的排序方式是使用ORDER BY子句。您可以为要取消透视的列添加别名(但需要更多工作),也可以仅将别名分配为CROSS APPLY中的值之一。

https://dbfiddle.uk/?rdbms=sqlserver_2017&fiddle=2ee6086ef661901542ba4d7a6b20181f

相关问题