从一个表中选择一个逗号分隔的值,并使用 SQL Server 中的函数在另一个表中的 where 条件中使用它
Posted
技术标签:
【中文标题】从一个表中选择一个逗号分隔的值,并使用 SQL Server 中的函数在另一个表中的 where 条件中使用它【英文标题】:Select a comma-separated value from one table and use it in where condition in another table using Functions in SQL Server 【发布时间】:2018-07-14 20:31:05 【问题描述】:我有一张表#table1
,列有num, codes
:
num codes
----------------------------
1 44.00,2724,02.10,50.02
2 786.59,44.0
还有另一个表#table2
,它从代码列中删除重复项并将其保存如下:
sno codes
----------
1 44.00
2 2724
3 02.10
4 50.02
5 786.59
现在我想选择#table1
中的每个逗号分隔值,并使用:
分隔符从#table2
打印其适当的sno
例如:
#table1
中第一行的结果:1:2:3:4
#table1
中第二行的结果:5:1
【问题讨论】:
select * from #table1 t1 left join #table2 t2 ON CHARINDEX(t2.codes, t1.codes) > 0
但在最后 2 行而不是 5,1 中显示 1,5
order by t1.num, CHARINDEX(t2.codes, t1.codes) asc
它可以工作@artm 谢谢
【参考方案1】:
一种方法是加入#table1
和#table2
,条件是后者的代码之一出现在第一个的CSV 列表中。然后,我们可以使用FOR XML PATH
进行汇总,以获得第一个表中每个数字的匹配sno
值列表。
SELECT
t1.codes,
STUFF((
SELECT ',' + CONVERT(varchar(10), t2.sno)
FROM table2 t2
WHERE ',' + t1.codes + ',' LIKE '%,' + t2.codes + ',%'
ORDER BY CHARINDEX(t2.codes, t1.codes)
FOR XML PATH('')), 1, 1, '') as list
FROM table1 t1;
codes list
1 44.00,2724,02.10,50.02 1,2,3,4
2 786.59,44.00 5,1
Demo
我在构建 CSV 时在此处进行了一些转换,但您可能需要做更多或更少的转换,具体取决于列的类型。特别是,我假设您所有的数字数据实际上都存储为文本。如果不是,那么上述查询可能不会产生您想要的完全匹配(例如,44.00
不会匹配 44
,即使两者实际上是相同的数字)。
连接条件使用了一个技巧。以下是使用硬编码数据的 LIKE
表达式示例:
WHERE ',44.00,2724,02.10,50.02,' LIKE '%,2724,%'
换句话说,我们搜索位于#table1
的给定记录中CSV字符串中任意位置的数字,两边都有逗号。
【讨论】:
我正在使用 sql server 2012 @tim @AshwanthKA 还有...?我的查询绝对应该在 SQL Server 2012 上运行,没有问题。查看演示。WITH table1 AS ( SELECT 1 AS num, '44.00,2724,02.10,50.02' AS codes UNION ALL SELECT 2, '786.59,44.00' ), table2 AS ( SELECT 1 AS sno, '44.00' AS codes UNION ALL SELECT 2, '2724' UNION ALL SELECT 3, '02.10' UNION ALL SELECT 4, '50.02' UNION ALL SELECT 5, '786.59' )
我的代码值可能会在每次执行时有所不同,您将其默认设置为如何将其更改为从运行时获取
我不明白你的评论。如果您的数据有问题导致上述查询无法正常工作,那么您有责任修复它。
在结果语句的第二行我需要结果为 5,1 而不是 1,5 ?@tim【参考方案2】:
如果list
列中的顺序很重要,您可以使用递归 cte。这是一个示例:
with t1 as (
select
*
from
(values (1, '44.00,2724,02.10,50.02')
, (2, '786.59,44.0')
) t (num, codes)
)
, t2 as (
select
*
from
(values (1, 44.00)
, (2, 2724)
, (3, 02.10)
, (4, 50.02)
, (5, 786.59)
)t (sno, codes)
)
, rcte as (
select
num, codes = cast(codes + ',' as varchar(8000)), charindex(',', codes) ci, list = cast('' as varchar(8000))
from
t1
union all
select
num, cast(stuff(a.codes, 1, ci, '') as varchar(8000)), charindex(',', stuff(a.codes, 1, ci, '')), cast(concat(a.list, ':', b.sno) as varchar(8000))
from
rcte a
join t2 b on substring(a.codes, 1, ci - 1) = b.codes
where
len(a.codes) > 0
)
select
num, list = stuff(list, 1, 1, '')
from
rcte
where
ci = 0
order by num
输出:
num list
--------------
1 1:2:3:4
2 5:1
【讨论】:
我需要这个而不使用 with 声明 这是一个recursive CTE
。如果没有with
声明,您将无法使用它。在这种情况下,您需要使用@Tim Biegeleisen 解决方案
我需要一个函数来动态发送数据以上是关于从一个表中选择一个逗号分隔的值,并使用 SQL Server 中的函数在另一个表中的 where 条件中使用它的主要内容,如果未能解决你的问题,请参考以下文章
如何把SQL数据表中一个字段的值按逗号分隔存入另外一个表,并删除重复记录?
Oracle PL/SQL 程序在源表中拆分逗号分隔的数据并推送到目标表中