【问题标题】:Adding value to column depending on LIKE根据 LIKE 向列添加值
【发布时间】:2017-12-09 02:32:38
【问题描述】:

我有 SSMS 2008 R2。这是我的桌子

PK | DateOf           | Other Columns | Items
01 | 05/30/2017 15:30 | Blah          | truck, elephant, apple, . . .
02 | 04/15/2012 07:07 | Bluh          | foot, orange, horse, . . .
03 | 11/01/2016 10:30 | Wham          | apple, screen, penny, . . .

我正在尝试在 Items 列中搜索每条记录并计算结果出现的次数。方便的是,每条记录只有一个水果,但如果解决方案能够处理多个水果(甚至可能是重复的),那就太酷了。上面的结果表如下所示

Count | Fruit
2     | Apple
1     | Orange

我有一份完整的“水果”清单。我试图弄清楚如何让它与 LIKE's 一起使用。

SELECT
count(PK) AS [Count]
??? AS [Fruit]
WHERE DateOf >= '2011-01-01 00:00' AND DateOf < '2012-01-01 00:00'
AND Items LIKE '%Apple%' --??(some kind of code that looks for the fruit values??)

【问题讨论】:

  • 修复你的数据结构。在分隔字符串中存储项目列表不是 SQLish 存储数据的方式。
  • 哦,相信我,如果我对此有任何控制权的话。这是一个赞助的 SQL Server,托管在我工作的公司的对面海岸。我唯一的访问权限是通过查询。出于某种原因,他们选择列出这样的项目
  • 您可以使用CHARINDEX 找到字符串的位置,然后使用SUBSTRING 将其拉出。像这样:stackoverflow.com/questions/10265841/…。但是你需要一个巨大的内联表达式才能把它弄出来

标签: sql sql-server


【解决方案1】:

这是存储列表的错误方式。但是,有时我们会被其他人非常糟糕的设计决定所困扰。

在这种情况下,您需要一个 split() 函数。 SQL Server 2016 提供了一个。您还可以在网络上找到一个代码(谷歌“SQL Server 拆分字符串”):

SELECT ss.fruit, count(*) AS [Count]
FROM t CROSS APPLY
     string_split(t.items) ss(fruit)
WHERE DateOf >= '2011-01-01' AND DateOf < '2012-01-01'
GROUP BY ss.fruit;

【讨论】:

  • +1 被困在糟糕的设计决策上。并且尽可能高效地处理糟糕的数据结构。
  • 这看起来像是我必须采取的路线。我将不得不对字符串拆分函数以及“CROSS APPLY”所做的任何事情进行一些研究。作为附录,实际上还有另一层我没有意识到的复杂性,“项目”列的格式实际上是这样的:[冰箱] 苹果、牛奶、草莓、[橱柜] 麦片、瑞士蛋糕卷
  • @Goatfarmer03 。 . .如果您想解决格式问题,请提出另一个问题。你的这个版本的问题已经有三个答案了。
【解决方案2】:

如果您的桌子上有水果,您可以使用简单的外部应用来识别水果。像这样:

drop table if exists dbo.Details;
drop table if exists dbo.Fruits;

create table dbo.Details (
    PK int not null primary key
    , DateOf datetime2(3)
    , Items varchar(100)
);

create table dbo.Fruits (
    Fruit varchar(100) not null primary key
);

insert into dbo.Details (PK, DateOf, Items)
values (1, '20170530 15:30', 'truck, elephant, apple, . . .')
    , (2, '20120415 07:07', 'foot, orange, horse, . . .')
    , (3, '20161101 10:30', 'apple, screen, penny, orange, . . .')

insert into dbo.Fruits (Fruit)
values ('apple'), ('orange');

select
    d.PK, d.DateOf, d.Items, count(*) as CountOfFruit
from dbo.Details d
    outer apply (
            select
            *
            from dbo.Fruits f
            where d.Items like '%' + f.Fruit + '%'
    ) tf
group by d.PK, d.DateOf, d.Items

【讨论】:

  • 这种方法的问题是它需要持续维护水果表,这可能是也可能不是问题,具体取决于实际数据的实际情况。
  • 谢谢,这也可以。水果列表已设置且不会更改。将测试此解决方案
【解决方案3】:

试试这个可能对你有帮助

IF OBJECT_ID('Tempdb..#Temp') IS NOT NULL
DROP TABLE #Temp

DECLARE @SearchWords nvarchar(max)='Apple,Orange'

DECLARE @Table TABLE (SearchWords nvarchar(max))
INSERT INTO @Table
SELECT @SearchWords

;With cte_Search
AS
(
SELECT  ROW_NUMBER()OVER(ORDER BY (SELECT 1) )AS Seq, 
        Split.a.value('.', 'VARCHAR(1000)') AS SearchWords
            FROM (
                SELECT
                     CAST('<S>' + REPLACE(SearchWords, ',', '</S><S>') + '</S>' AS XML) AS SearchWords
                FROM @Table
                ) AS A
            CROSS APPLY SearchWords.nodes('/S') AS Split(a)

)
SELECT * INTO #Temp  FROM cte_Search


;With CTE (PK , DateOf , OtherColumns , Items)
AS
(
SELECT 01 , '05/30/2017 15:30' ,'Blah', 'truck, elephant, apple'UNION ALL
SELECT 02 , '04/15/2012 07:07' ,'Bluh', 'foot, orange, horse'   UNION ALL
SELECT 03 , '11/01/2016 10:30' ,'Wham', 'apple, screen, penny'
)
SELECT SearchWords AS Fruit,
        MAX(Seq) AS CountOFFruits FROM
(
SELECT C.OtherColumns,
        t.SearchWords,
        C.Items,
        COUNT(C.Items) CntItems,
        ROW_NUMBER()OVER(Partition by t.SearchWords order by  C.OtherColumns ) AS Seq
         FROM CTE c ,#Temp t
WHERE CHARINDEX(t.SearchWords,c.Items) >0
Group by C.OtherColumns,t.SearchWords,C.Items
)dt
Group by SearchWords

结果

Fruit   CountOFFruits
----------------------
Apple   2
Orange  1

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2023-03-30
    • 1970-01-01
    • 2021-12-02
    • 2015-04-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多