簡體   English   中英

SQL內部聯接多對多實例的存在

[英]SQL inner join many to many instances existance

我有兩張桌子

Campaigns ( name, date, url, etc. )
campaign_tags ( campaign_name, tag ) 

我正在嘗試選擇所有具有標簽列表的廣告系列,即

SELECT * 
from campaigns
inner join campaign_tags on campaigns.name=campaign_tags.name
where ( list of campaign tags ) in ( list of tags ) 

我有標簽列表(它們是用“,”分隔的字符串),我想要在列表中包含所有標簽的廣告系列。 我怎樣才能做到這一點?

編輯; 樣本數據:

Campaign: "MyCampaign", "22/11/2017","https://stackoverflow.com/posts/47431394" "MyCampaign2", "22/11/2017","https://stackoverflow.com/posts/47431394" CampaignTags: "MyCampaign","sports" "MyCampaign","stackoverflow" "MyCampaign","Life" "MyCampaign2","food"

如果要查詢的列表是"sports","life",stackoverflow","health","programming" ,則應該出現” MyCampaign“,” 22/11/2017“等,因為它的所有標簽都是包括在列表中,但不應該包含“ MyCampaign2”;如果我要查詢"food","sports" ,則應該顯示“ MyCampaign2”,如果我要查詢“ sports”,則應該不顯示任何內容。

這樣一來,那些擁有這些標簽的廣告系列將不再是單個標簽,而是所有這些標簽

SELECT c.*
FROM campaigns c
INNER JOIN campaign_tags ct ON c.name=ct.name
WHERE ct.tag IN ( "sports","life" )
GROUP BY c.name
HAVING COUNT(DISTINCT ct.tag) = SUM(ct.tag IN ( "sports","life" )) 

演示

作為變體

SELECT *
FROM Campaigns
WHERE name IN(
          SELECT campaign_name
          FROM campaign_tags
          WHERE tag IN("sports","life")
          GROUP BY campaign_name
          HAVING COUNT(tag)=LENGTH('"sports","life"')-LENGTH(REPLACE('"sports","life"',',',''))+1 -- count of tags
        )

SQL小提琴- http://sqlfiddle.com/#!9/8870c/10

新條件的第二個變體

SELECT *
FROM Campaigns
WHERE name IN(
          SELECT campaign_name
          FROM campaign_tags
          GROUP BY campaign_name
          HAVING
            COUNT(CASE
                    WHEN tag IN("sports","life","stackoverflow","health","programming")
                    THEN tag
                  END)=COUNT(tag)
        )

SQL小提琴- http://sqlfiddle.com/#!9/ed1294/12

如果標簽可以在表格中復制,也可以使用DISTINCT

SELECT *
FROM Campaigns
WHERE name IN(
          SELECT campaign_name
          FROM campaign_tags
          GROUP BY campaign_name
          HAVING
            COUNT(DISTINCT CASE
                    WHEN tag IN("sports","life","stackoverflow","health","programming")
                    THEN tag
                  END)=COUNT(DISTINCT tag)
        )

SQL小提琴- http://sqlfiddle.com/#!9/ed1294/13

抱歉,此解決方案僅適用於sqlserver,未能看到它適用於mysql。 但會因為對其他人有用而離開。 Charindex可以用Locate函數代替,但是mysql不支持WITH

該解決方案查找在搜索字符串中具有所有標簽的所有廣告系列

該解決方案很容易實現您希望搜索的價值。

唯一需要注意的是,任何標簽都不能包含“,”。 如果可能發生這種情況,則需要另一個定界符。 也不會在搜索字符串中容納重復的標簽。

作為記錄,使用campaign_id會更好地進行聯接

create table c
    (
        thename varchar(100),
        thedate datetime,
        theurl  varchar(100)
    )

create table ctags
(
    thename varchar(100),
    thetag  varchar(100)
)

create unique index c_u1 on c(thename)
create unique index ctags_u1 on ctags(thename,thetag)


insert into c values ('mycampaign_good1','20170101','http://127.0.0.1')
insert into c values ('mycampaign_bad1','20170101','http://127.0.0.1')

insert into ctags values ('mycampaign_good1','sports')
insert into ctags values ('mycampaign_good1','stackoverflow')
insert into ctags values ('mycampaign_good1','programming')

insert into ctags values ('mycampaign_bad1','sports')
insert into ctags values ('mycampaign_bad1','stackoverflow')
insert into ctags values ('mycampaign_bad1','life')

/* only good1 succeeds*/
with searchstr as
(
   select 'programming,sports,stackoverflow' str
),
numvals as
(
    select len(searchstr.str) - len(replace(searchstr.str,',',''))+1 n
    from searchstr
)
select  c.thename
from c join ctags on c.thename = ctags.thename
where charindex (','+ctags.thetag,','+(select str from searchstr)) >0
group by c.thename 
having count(*) = (select numvals.n from numvals)
;
/* both succeed */
with searchstr as
(
   select 'sports,stackoverflow' str
),
numvals as
(
    select len(searchstr.str) - len(replace(searchstr.str,',',''))+1 n
    from searchstr
)
select  c.thename
from c join ctags on c.thename = ctags.thename
where charindex (','+ctags.thetag,','+(select str from searchstr)) >0
group by c.thename 
having count(*) = (select numvals.n from numvals)
;
/* both fail as neither have friends */
with searchstr as
(
   select 'friends,sports,stackoverflow' str
),
numvals as
(
    select len(searchstr.str) - len(replace(searchstr.str,',',''))+1 n
    from searchstr
)
select  c.thename
from c join ctags on c.thename = ctags.thename
where charindex (','+ctags.thetag,','+(select str from searchstr)) >0
group by c.thename 
having count(*) = (select numvals.n from numvals)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM