【问题标题】:Return tag string based on two conditions根据两个条件返回标签字符串
【发布时间】:2016-06-19 10:50:57
【问题描述】:

我有一个带有 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

【问题讨论】:

  • 能否请您添加一些示例预期输出,并进一步说明您的要求
  • 是的,很抱歉不清楚。输出将是带有字符串“storage”的所有行,或者仅作为内容,也可以带有位置字符串之一,例如:“storage”或“storage,location1”或“location2,storage”。我需要过滤掉所有带有字符串“storage”的行和一些其他文本而不是任何位置。
  • 请编辑您的问题以包括相关表格 DDL 语句、作为 DML 语句的示例数据和所需结果。
  • 无 DDL。 DML 在上面(我认为)。期望的结果在问题和上面的评论中解释了两次。我只需要有人可以帮助我弄清楚如何只返回字符串中包含特定单词和/或位置的记录...

标签: sql-server tsql


【解决方案1】:

“查找...的所有记录”您的查询应更改为:

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

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

如果您希望查询返回所有行并简单地指出某行是否与您的标记条件匹配(如您给出的示例查询),则将所有 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

以后请提供与上述类似的示例表。

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

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

【讨论】:

  • 哇 - 非常感谢,亚历克斯!我会记住示例表。现在我该如何接受你的回答、给你分数、结束问题或其他什么...?
  • 答案(我的答案)分数下方有一个大的“勾号”。这将接受答案。
  • 我只在最后一个查询中得到正确的结果——工作示例。另外两个返回的记录不是位置和存储。难道我做错了什么?我用 'item' 替换了 'Value',因为我在 string 函数中没有 'Value',但是标签字符串被分成了几个 'item'(每个单词)。我看到了勾号 - 谢谢:)。
  • @preston,请参阅我的答案底部的 更新。基本上,您需要找出函数返回的列的名称并使用该列
  • 谢谢亚历克斯。在我的情况下,列名是“项目”,当我使用它时,我似乎得到了错误的结果。我会尝试一些不同的事情并回帖-这可能是我的错误!我刚刚在问题中发布了拆分字符串函数。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-07-19
  • 2022-08-12
  • 2023-02-08
相关资源
最近更新 更多