sql - 传入多个 Id 以返回 case 语句中的列
问题描述
我正在使用一些动态 SQL 根据订阅类型返回一些列。我遇到的问题是多种订阅类型。虽然我可以胜任处理 1 种订阅类型。我不知道如何处理 2 种订阅类型。我总共有 8 种不同的类型。
例如:
DECLARE @subType tinyint = 2
DECLARE @Id varchar(4) = 'U01'
DECLARE @SQLProjectDetails nvarchar(MAX)
SET @SQLProjectDetails = N'SELECT ' +
STUFF(
-- General Information
CASE WHEN @subType IN (1,2,3,4) THEN N',' + NCHAR(13) +
NCHAR(10) + N' wf1.Id' ELSE N'' END +
CASE WHEN @subType IN (1,2) THEN N',' + NCHAR(13) +
NCHAR(10) + N' wf1.Name' ELSE N'' END +
CASE WHEN @subType IN (5,6,8) THEN N',' + NCHAR(13) +
NCHAR(10) + N' wf1.OtherNames' ELSE N'' END +
CASE WHEN @subType IN (1,2) THEN N',' + NCHAR(13) +
NCHAR(10) + N' wf1.CountryName' ELSE N'' END +
, 1, 10,N'') + NCHAR(13) + NCHAR(10) +
N'FROM Table wf1where (wf1.Id= @p)';
EXEC sp_executesql @SQLProjectDetails, N'@p varchar(4)', @p = @Id;
但是,如果我他们的订阅类型为 2 和 5,该怎么办?
那么 othernames 列也会被返回吗?我遇到的主要问题是 8 种不同的订阅类型。虽然我可以尝试涵盖所有可能的可能性,但我更愿意动态地执行此操作(主要是因为有 40000 多种不同的变化)。
解决方案
如果你有一个这样的 ColLookup 表:
SubType, ColumnName
1,wf1.Id
2,wf1.Id
3,wf1.Id
4,wf1.Id
1,wf1.Name
2,wf1.Name
5,wf1.OtherNames
6,wf1.OtherNames
8,wf1.OtherNames
1,wf1.CountryName
2,wf1.CountryName
然后像这样的 SQL 将为您提供您应该提取的列名:
SELECT
STRING_AGG(l.ColumnName, ',') as ColList
FROM
otherTable o
INNER JOIN
ColLookup l on o.subtype = l.subtype
WHERE
o.id = 1234
如果 o.id 1234 的子类型为 1,则此 SQL 将返回
'wf1.Id,1,wf1.Name,wf1.CountryName'
如果 o.id X 的子类型为 3,则此 SQL 将返回
'wf1.Id'
使其成为完整的 SQL 可能类似于:
SELECT
CONCAT('SELECT ', STRING_AGG(l.ColumnName, ','), ' FROM blah') as sq
FROM
otherTable o
INNER JOIN
ColLookup l on o.subtype = l.subtype
WHERE
o.id = 1234
您可以将其分配给变量并执行它
如果您的 SQLS 是 2017 年之前的版本并且没有 STRING_AGG,请使用类似的方法将多行连接成一个字符串,例如 STUFF/FOR XML PATH。如果需要定义的顺序,请在查找表中添加一个顺序列(STRING_AGG 有 WITHIN GROUP ORDER BY 选项,我相信其他方法也有更改连接字符串顺序的选项)
确实,我会在 C# 中执行此操作。我将运行选择所有内容的主查询,然后运行:
SELECT ColName FROM ColLookup WHERE SubType in (1,5)
我将它放入字典/哈希集(这使用 linq 伪代码,但是你想要):
//this is a union - anything 1 can see or 5 can see
var dict = dbcontext.Wf1Table.Where(r => r == 1 || r == 5).Distinct().ToDictionary(r => r.ColumnName, r => r.ColumnName)
//this is an intersect - anything common to 1 and 5 only
var dict = dbcontext.Wf1Table.Where(r => r == 1).Intersect(dbcontext.Wf1Table.Where(r => r == 5)).ToDictionary(r => r.ColumnName, r => r.ColumnName)
//this is if you downloaded the columns into a datatable
//SELECT DISTINCT colname FROM t WHERE subtype IN (1,5) --union
//SELECT colname FROM t WHERE subtype IN (1,5) GROUP BY colname HAVING COUNT(*) = 2 --intersection
var dict = new Dictionary(string, string);
foreach(var ro in colnamedatatable)
dict[ro.ColName] = null;
我会将我的主要查询拉入数据表并删除不需要的列:
for(int c = datatable.Columns.Length -1; c >= 0; c--) //gobackwards
if(!dict.ContainsKey(datatable.Columns[c].ColumnName))
datatable.Columns.RemoveAt(c);
如果你想在 SQL 中坚持这样做,这将给出一个相交:
SELECT
CONCAT('SELECT ', STRING_AGG(l.ColumnName, ','), ' FROM blah') as sq
FROM
otherTable o
INNER JOIN
ColLookup l on o.subtype = l.subtype
WHERE
o.id = @id
GROUP BY
l.ColumnName
HAVING COUNT(*) = @count_of_subtypes_for_that_id
有些东西需要知道给定 ID 有多少子类型;数据库知道,但很难在这方面为您提供指导,因为您还没有说明数据是如何存储的。如果正确(多个 ID 记录/中间人表),则此查询有效。如果它是“逗号分隔列表”,那么(呃)它需要解析成两行
推荐阅读
- javascript - 元素/值的每个更改列表上的 JavaScript 计数器为零(从零开始)
- flutter - 在颤动的输入字段上键入时如何更改文本字段
- ios - 如何将与现实世界对象的碰撞应用到 RealityKit 中的 3D 对象 (.usdz)?
- laravel - Laravel:电子邮件未从服务器发送
- java - Java PriorityQueue Comparator 在特定条件下插入二维数组
- javascript - 如何使用 each 和 image.onload 保留数组的顺序
- javascript - api在axios中被阻止
- python - 如何使用 python 脚本在没有熊猫的情况下进行 vlookup
- window - 如何创建具有多个条件计数的 siddhi 应用程序
- html - 配售里面的标签