我有一个功能,用户可以在某个租户中分配多个类别(食物,非食物等)。请参见示例数据表
表:tblSales
date tenant sales category
1/1/2015 tenant1 1000 Food,Non-Food,Kiosk
1/1/2015 tenant2 2000 Food
1/1/2015 tenant3 1000 Non-Food,Kiosk
当用户选择“类别列”中列出的任何类别时,系统应该能够加载记录。
例如,用户选择的类别:非食品,信息亭。预期结果应为:
date tenant sales category
1/1/2015 tenant1 1000 Food,Non-Food,Kiosk
1/1/2015 tenant3 1000 Non-Food,Kiosk
因为非食品和报亭出现在租户1和3中。
所以,我认为,该过程应首先对Category列的值进行字符串操作,将每个单词分隔为逗号。我的代码无法正常工作
@Category nvarchar(500) = 'Non-Food,Kiosk' --User selected
SELECT date,tenant,sales,category
FROM tblSales
WHERE (category in (SELECT val FROM dbo.split (@Category, @delimeter)))
这似乎不起作用,因为它分裂的是用户选择的类别而不是数据本身的值。我试过这个
@Category nvarchar(500) = 'Non-Food,Kiosk' --User selected
SELECT date,tenant,sales,category
FROM tblSales
WHERE ((SELECT val FROM dbo.split (category, @delimeter)) in (SELECT val FROM dbo.split (@Category, @delimeter)))
但是这导致了这个错误
子查询返回的值超过1。当子查询遵循=,!=,<,< =,>,> =或子查询用作表达式时,不允许这样做。
答案 0 :(得分:1)
通常,将CSV数据存储到数据库列中是不好的做法,因为正如您目前所看到的,它会呈现数据库无法使用的许多优点。
但是,我认为你可以通过使用LIKE
来逃脱。假设用户选择了类别Non-Food
和Kiosk
,您可以尝试以下查询:
SELECT date,
tenant,
sales,
category
FROM tblSales
WHERE category LIKE 'Non-Food' OR
category LIKE 'Kiosk'
答案 1 :(得分:1)
除了Tim的回答(他对数据库中的CSV字段绝对正确!)请注意,SQL Server 2016引入了STRING_SPLIT
函数。对于单个类别,它就像:
SELECT
date
,tenant
,sales
,category
FROM tblSales
WHERE @Category IN (SELECT value FROM STRING_SPLIT(category, ','))
对于以逗号分隔的类别列表,您必须与EXISTS
一起使用两次:
WHERE EXISTS
(
SELECT *
FROM STRING_SPLIT(category, ',')
WHERE value IN (SELECT value FROM STRING_SPLIT(@Category, ','))
)
如果您使用的是较旧的SQL Server版本,则可以编写自己的STRING_SPLIT
函数,请查看T-SQL split string。您可以使用与上面相同的语法来使用该函数(请注意我在这里编写代码并且未经测试,因此您可能需要一些修复)。
关于性能的注意事项:从QP你可以检查子查询的执行方式,从天真的角度来看我会说CTE,临时表和子查询具有大致相同的性能(在这个简单的例子中)但是如果此代码对性能至关重要,则最好执行一些基准测试(使用实际数据和实际访问方案)。
答案 2 :(得分:0)
尝试使用以下代码。
创建一个拆分删除字符串的函数。
CREATE FUNCTION SplitWords
(
@Input NVARCHAR(MAX),
@Character CHAR(1)
)
RETURNS @Output TABLE (
Item NVARCHAR(1000)
)
AS
BEGIN
DECLARE @StartIndex INT, @EndIndex INT
SET @StartIndex = 1
IF SUBSTRING(@Input, LEN(@Input) - 1, LEN(@Input)) <> @Character
BEGIN
SET @Input = @Input + @Character
END
WHILE CHARINDEX(@Character, @Input) > 0
BEGIN
SET @EndIndex = CHARINDEX(@Character, @Input)
INSERT INTO @Output(Item)
SELECT SUBSTRING(@Input, @StartIndex, @EndIndex - 1)
SET @Input = SUBSTRING(@Input, @EndIndex + 1, LEN(@Input))
END
RETURN
END
GO
在prcedure / script中创建一个输入tabl,并将拆分数据保存在其中。这里输入的是@Category
DECLARE @input TABLE (item VARCHAR(50))
INSERT INTO @input
SELECT Item
FROM [dbo].SplitWords (@Category, ',')
使用like运算符与实际表格进行联接
SELECT DISTINCT a.date,
a.tenant,
a.sales,
a.category
FROM tblSales s
JOIN @input a
ON category LIKE '%'+item+'%'
答案 3 :(得分:0)
您可以尝试使用SQL Select语句,其中我使用了用户定义的SQL function for split string任务
declare @Category nvarchar(500) = 'Non-Food,Kiosk'
declare @cnt int = (select COUNT(*) from dbo.SPLIT(@Category,','))
;with cte as (
select
t.*, COUNT(*) over (partition by tenant) cnt
from dbo.SPLIT(@Category,',') u
inner join (
select
tblSales.*, c.val
from tblSales
cross apply dbo.SPLIT(tblSales.category,',') c
) t on u.val = t.val
)
select distinct tenant from cte where cnt = @cnt