根据两个条件返回标记字符串

时间:2016-06-19 10:50:57

标签: sql-server tsql

我有一个包含Tags列的表格,其中包含以下内容:'server, network, location1' ...

我需要查找项目' storage'存在 和 存在任何这些位置的地方('location1', location2, location3') 和 没有其他项目存在的情况(即只有' storage'和location或者只有' storage')。

我使用函数将字符串拆分为项目,因此下面代码的select语句使用整个字符串的标签和项目的项目将对我有所帮助。

SELECT cardid, item, tags, count(1) as Total
, result = 
    case when lower(item) = 'storage' and
    lower(item) in 'location1, location2, location3' 
    then 'yes'
    else 'no'
    end
FROM myTable 
    CROSS APPLY dbo.fn_SplitString(Tags, ',')
GROUP BY cardid, item, tags 
order by item desc

这是我使用的功能:

CREATE FUNCTION [dbo].[fn_SplitString]   
(   
    @String VARCHAR(8000),   
    @Delimiter VARCHAR(255)   
)   
RETURNS   
@Results TABLE   
(   
    ID INT IDENTITY(1, 1),   
    Item VARCHAR(8000)   
)   
AS   
BEGIN   
INSERT INTO @Results (Item)   
SELECT SUBSTRING(@String+@Delimiter, Number,   
    CHARINDEX(@Delimiter, @String+@Delimiter, Number) - Number)   
FROM Numbers   
WHERE Number <= LEN(REPLACE(@String,' ','|'))   
AND SUBSTRING(@Delimiter + @String,   
            Number,   
            LEN(REPLACE(@delimiter,' ','|'))) = @Delimiter   
ORDER BY Number RETURN   
END

1 个答案:

答案 0 :(得分:0)

&#34;查找所有记录......&#34;您的查询应更改为:

SELECT MT.cardid, MT.tags, count(1) as Total
FROM myTable AS MT
    CROSS APPLY dbo.fn_SplitString(Tags, ',') AS TagList
GROUP BY MT.cardid, MT.tags
HAVING COUNT( * ) =
        COUNT( CASE WHEN TagList.Item IN( 'location1', 'location2', 'location3' ) THEN 1 ELSE NULL END )
        + COUNT( CASE WHEN TagList.Item = 'storage' THEN 1 ELSE NULL END )
    AND COUNT( CASE WHEN TagList.Item = 'storage' THEN 1 ELSE NULL END ) >= 1
ORDER BY MT.cardid DESC

上述查询正在使用&#34;条件聚合&#34;。我添加了HAVING子句,其中所有标签的每个组COUNT都与&#34;位置&#34;的总和进行比较。标签COUNT和&#34;存储&#34;标记COUNT。下一个条件检查&#34;存储&#34;的COUNT。大于或等于1(如果只需要1个存储元素而不是将其更改为= 1
注意:我假设您的dbo.fn_SplitString函数返回一个表格,其中包含名为&#34; Item&#34;。的列 注意2:请注意我已为该函数指定了别名(&#34; AS TagList&#34;)。

如果您希望查询返回所有行,只需指示行是否与您的标记条件匹配(例如您提供的示例查询),请将所有HAVING条件移至CASE语句并删除HAVING

SELECT MT.cardid, MT.tags, COUNT(*) as Total
, result = 
    CASE
        WHEN COUNT( * ) =
                COUNT( CASE WHEN TagList.Value IN( 'location1', 'location2', 'location3' ) THEN 1 ELSE NULL END )
                + COUNT( CASE WHEN TagList.Value = 'storage' THEN 1 ELSE NULL END )
            AND COUNT( CASE WHEN TagList.Item = 'storage' THEN 1 ELSE NULL END ) >= 1
    THEN 'yes'
    ELSE 'no'
    END
FROM myTable AS MT
    CROSS APPLY dbo.fn_SplitString(Tags, ',') AS TagList
GROUP BY MT.cardid, MT.tags
ORDER BY MT.cardid DESC

以下是一个工作示例:

DECLARE @Sample TABLE( GroupID INT, Tag VARCHAR( 20 ))
INSERT INTO @Sample( GroupID, Tag )
VALUES
( 1, 'location1' ),( 1, 'location2' ), ( 1, 'storage' ),
( 2, 'location1' ),( 2, 'location2' ), ( 2, 'something else' ),
( 3, 'storage' )

SELECT GroupID
FROM @Sample AS TagList
GROUP BY GroupID
HAVING COUNT( * ) =
        COUNT( CASE WHEN TagList.Tag IN( 'location1', 'location2', 'location3' ) THEN 1 ELSE NULL END )
        + COUNT( CASE WHEN TagList.Tag = 'storage' THEN 1 ELSE NULL END )
    AND COUNT( CASE WHEN TagList.Tag = 'storage' THEN 1 ELSE NULL END ) >= 1

将来请提供如上所示的样本表。

更新(回答您的意见):
请注意,下面的函数是一个表值函数,它返回一个包含一列的表:@Results TABLE( Value VARCHAR( MAX ))。列的名称是&#34;值&#34; (在您的情况下,它可能是一个不同的名称)。因此,在查询中访问此函数返回的数据时,请指定此列的名称(在我的情况下,它是&#34;值&#34;)。

CREATE FUNCTION dbo.fn_SplitString
(
    @Source VARCHAR( MAX ),
    @Delimiter VARCHAR( 100 )
)
RETURNS @Results TABLE( Value VARCHAR( MAX ))
AS
BEGIN
    -- The main body of code has been excluded for brevity
END

链接到包含解释的类似问题:
T-SQL SUM All with a Conditional COUNT
Create a view with totals from multiple columns
SQL Server - conditional aggregation with correlation