如何在SQL中返回所有列名的组合列表,当每个列名的输出等于1(TRUE)时?

huangapple go评论74阅读模式
英文:

How do I return a list of all combinations of column names in SQL, when the output for each of those column names equates to 1 (TRUE)?

问题

以下是翻译好的部分:

例如,这是一个示例数据集,其中ID、A、B、C是我的列名:

ID	A	B	C
L1	1	0	1
L2	1	1	1
L3	0	0	1

以下是我希望输出显示的内容,当该列名的值等于1时:

ID	组合
L1	A
L1	C
L1	A,C
L2	A
L2	B
L2	C
L2	A,B
L2	B,C
L2	A,C
L2	A,B,C

等等...

请注意,这只是我的数据集外观的示例表示,我希望输出应该是什么样子。在我的实际数据集中,我有100多列和几百万行。

英文:

For example, here's what a sample dataset looks like in which ID, A, B, C are my column names:

ID	A	B	C
L1	1	0	1
L2	1	1	1
L3	0	0	1

Here's what I would like the output to show, when the value of that column name equates to 1:

ID	Combination
L1	A
L1	C
L1	A,C
L2	A
L2	B
L2	C
L2	A,B
L2	B,C
L2	A,C
L2	A,B,C

and so on...

Please note this is just a sample representation of what my dataset looks like, and what I am hoping the output should look like. In my actual dataset, I have over a 100 columns and a few million rows.

答案1

得分: 4

你可以使用CROSS APPLY来有效地将起始数据与一对值进行连接 - 一个是空值(始终存在),另一个是非空值(有条件存在)。针对每个源列重复此操作,然后将这些中间结果连接起来。

对于最后一步,CONCAT_WS()函数将很好地处理空值和非空值的组合,并在适当位置插入分隔符(逗号)。添加一个检查来排除空情况,你应该能够获得所需的结果。

SELECT DS.ID, Result.Combination
FROM Dataset DS
CROSS APPLY (
    SELECT CAST(NULL AS VARCHAR(2)) AS Value
    UNION ALL
    SELECT 'A' WHERE DS.A = 1
) A
CROSS APPLY (
    SELECT CAST(NULL AS VARCHAR(2)) AS Value
    UNION ALL
    SELECT 'B' WHERE DS.B = 1
) B
CROSS APPLY (
    SELECT CAST(NULL AS VARCHAR(2)) AS Value
    UNION ALL
    SELECT 'C' WHERE DS.C = 1
) C
CROSS APPLY (
    SELECT CONCAT_WS(',', A.Value, B.Value, C.Value) AS Combination
) Result
WHERE Result.Combination > ''
ORDER BY
    DS.ID,
    LEN(Result.Combination),
    Result.Combination

以下是一个更紧凑的变体:

SELECT DS.ID, Result.Combination
FROM Dataset DS
CROSS APPLY (SELECT 'A' AS Val WHERE DS.A = 1 UNION ALL SELECT NULL) A
CROSS APPLY (SELECT 'B' AS Val WHERE DS.B = 1 UNION ALL SELECT NULL) B
CROSS APPLY (SELECT 'C' AS Val WHERE DS.C = 1 UNION ALL SELECT NULL) C
CROSS APPLY (SELECT CONCAT_WS(',', A.Val, B.Val, C.Val) AS Combination) Result
WHERE Result.Combination > ''
ORDER BY DS.ID, LEN(Result.Combination), Result.Combination

请参考此db<>fiddle以查看演示。

结果:

ID Combination
L1 A
L1 C
L1 A,C
L2 A
L2 B
L2 C
L2 A,B
L2 A,C
L2 B,C
L2 A,B,C
L3 C

如果你需要处理许多列,你可以考虑查看生成所需查询的动态SQL技术,可能会得到类似这样的结果

英文:

You can use CROSS APPLYs to effectively join your starting data with a pair of values - one null value (always present) and and one non-null value (conditionally present). Repeat for each source column and then concatenate those intermediate results.

For that last step, the CONCAT_WS() function will nicely handle the combination of null and non-null values while inserting delimiters (commas) in the appropriate places. Add a check to exclude the empty case and you should have the desired results.

SELECT DS.ID, Result.Combination
FROM Dataset DS
CROSS APPLY (
    SELECT CAST(NULL AS VARCHAR(2)) AS Value
    UNION ALL
    SELECT &#39;A&#39; WHERE DS.A = 1
) A
CROSS APPLY (
    SELECT CAST(NULL AS VARCHAR(2)) AS Value
    UNION ALL
    SELECT &#39;B&#39; WHERE DS.B = 1
) B
CROSS APPLY (
    SELECT CAST(NULL AS VARCHAR(2)) AS Value
    UNION ALL
    SELECT &#39;C&#39; WHERE DS.C = 1
) C
CROSS APPLY (
    SELECT CONCAT_WS(&#39;,&#39;, A.Value, B.Value, C.Value) AS Combination
) Result
WHERE Result.Combination &gt; &#39;&#39;
ORDER BY
    DS.ID,
    LEN(Result.Combination),
    Result.Combination

Here is a more compact variation:

SELECT DS.ID, Result.Combination
FROM Dataset DS
CROSS APPLY (SELECT &#39;A&#39; AS Val WHERE DS.A = 1 UNION ALL SELECT NULL) A
CROSS APPLY (SELECT &#39;B&#39; AS Val WHERE DS.B = 1 UNION ALL SELECT NULL) B
CROSS APPLY (SELECT &#39;C&#39; AS Val WHERE DS.C = 1 UNION ALL SELECT NULL) C
CROSS APPLY (SELECT CONCAT_WS(&#39;,&#39;, A.Val, B.Val, C.Val) AS Combination) Result
WHERE Result.Combination &gt; &#39;&#39;
ORDER BY DS.ID, LEN(Result.Combination), Result.Combination

See this db<>fiddle for a demo.

Results:

ID Combination
L1 A
L1 C
L1 A,C
L2 A
L2 B
L2 C
L2 A,B
L2 A,C
L2 B,C
L2 A,B,C
L3 C

If you have many columns to deal with, you might consider looking into dynamic SQL techniques to generate the needed query, which might yield something like this.

答案2

得分: 0

以下是已翻译的代码部分:

以下代码在 [dbfiddle](https://dbfiddle.uk/Ae3YAH7g) 中可用,演示了一种方法。您可以在通用表达式 (CTE) 的末尾使用备用的 `select` 语句来查看中间结果,以更好地理解涉及的步骤。

-- 示例数据。
declare @Samples as Table ( Id VarChar(2), A Int, B Int, C Int );
insert into @Samples ( Id, A, B, C ) values
  ( 'L1', 1, 0, 1 ),
  ( 'L2', 1, 1, 1 ),
  ( 'L3', 0, 0, 1 );
select * from @Samples;

-- 查询数据。
with
  ConvertedColumns as (
    -- 将非 Id 列从数字转换为字符串。
    select S.Id, Cols.AC, Cols.BC, Cols.CC
      from @Samples as S
        cross apply ( select
          case when S.A = 1 then 'A' end as AC,
          case when S.B = 1 then 'B' end as BC,
          case when S.C = 1 then 'C' end as CC ) as Cols ),
  Combos as (
    -- 生成所有有趣的值组合。
    select CCols.Id, CCols.AC, CCols.BC, CCols.CC
      from ConvertedColumns as CCols
      group by cube ( Id, AC, BC, CC )
      having Id is not NULL ),
  ExtendedCombos as (
    -- 使用逗号分隔的值和列计数扩展组合。
    select Id, X1.CSL, X2.ZBColumns
      from Combos
      cross apply (
        -- 生成逗号分隔的列值列表。
        select Concat_WS( ',', AC, BC, CC ) as CSL ) as X1
      cross apply (
        -- 计算 CSL 中列的零基编号。
        --   这是一个老的技巧,假设列值中没有逗号。
        --   这样,即使某些列值具有不同的长度,我们仍然可以正确地对结果进行排序。
        select Len( X1.CSL ) - Len( Replace( X1.CSL, ',', '' ) ) as ZBColumns ) as X2
      where X1.CSL != '' )
    -- 您可以使用备用的   select   语句查看中间结果。
--  select * from ConvertedColumns;
--  select * from Combos;
--  select * from ExtendedCombos;
  select distinct Id, CSL, ZBColumns
    from ExtendedCombos
    order by
      -- 按   Id   排序...
      Id,
      -- ...以及组合中的列数...
      ZBColumns,
      -- ...最后是组合本身。
      CSL;

希望这对您有帮助。如果您有任何其他问题,请随时提问。

英文:

The following code, available in a dbfiddle, demonstrates one approach. You can use the alternate select statements at the end of the common table expression (CTE) to examine the intermediate results and better understand the steps involved.

-- Sample data.
declare @Samples as Table ( Id VarChar(2), A Int, B Int, C Int );
insert into @Samples ( Id, A, B, C ) values
( &#39;L1&#39;, 1, 0, 1 ),
( &#39;L2&#39;, 1, 1, 1 ),
( &#39;L3&#39;, 0, 0, 1 );
select * from @Samples;
-- Query the data.
with
ConvertedColumns as (
-- Convert the non-Id columns from numbers to strings.
select S.Id, Cols.AC, Cols.BC, Cols.CC
from @Samples as S
cross apply ( select
case when S.A = 1 then &#39;A&#39; end as AC,
case when S.B = 1 then &#39;B&#39; end as BC,
case when S.C = 1 then &#39;C&#39; end as CC ) as Cols ),
Combos as (
-- Generate all of the interesting combinations of values.
select CCols.Id, CCols.AC, CCols.BC, CCols.CC
from ConvertedColumns as CCols
group by cube ( Id, AC, BC, CC )
having Id is not NULL ),
ExtendedCombos as (
-- Extend the combinations with the comma-separated list of values and column counts.
select Id, X1.CSL, X2.ZBColumns
from Combos
cross apply (
-- Generate the comma-separated list of column values.
select Concat_WS( &#39;,&#39;, AC, BC, CC ) as CSL ) as X1
cross apply (
-- Calculate the zero-based number of columns in the CSL.
--   Old trick that assumes none of the column values contain commas.
--   This lets us properly sort the results even if some column values have
--     varying lengths.
select Len( X1.CSL ) - Len( Replace( X1.CSL, &#39;,&#39;, &#39;&#39; ) ) as ZBColumns ) as X2
where X1.CSL != &#39;&#39; )
-- You can use the alternate   select   stamenets to see the intermediate results.
--  select * from ConvertedColumns;
--  select * from Combos;
--  select * from ExtendedCombos;
select distinct Id, CSL, ZBColumns
from ExtendedCombos
order by
-- Order by the   Id   ...
Id,
-- ... and the number of columns in the combination ...
ZBColumns,
-- ... and finally the combinations themselves.
CSL;

huangapple
  • 本文由 发表于 2023年7月18日 04:28:04
  • 转载请务必保留本文链接:https://go.coder-hub.com/76707880.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定