oracle 更正SQL以检查错误的组合

4dbbbstv  于 2023-11-17  发布在  Oracle
关注(0)|答案(3)|浏览(165)

我在一个oracle sql数据库中工作,有两个表,一个有一个坏属性组合列表,另一个有一个用户及其属性列表。像这样:
| ComboID| Item1| Item2|
| --|--|--|
| 1 |冰淇淋|热酱料|
| 2 |芦笋|巧克力|
| 3 |花生酱|牛排|
| 4 |芦笋|冰淇淋|
| 用户属性ID|用户|项目|
| --|--|--|
| 1 |A1|冰淇淋|
| 2 |B2|芦笋|
| 3 |A1|巧克力|
| 4 |B2|冰淇淋|
| 5 |C3|牛排|
| 6 |C3|冰淇淋|
| 7 |C3|巧克力|
在本例中,我希望标记用户B2,而不是A1或C3。
我的预期结果是这样的:
| 用户|Bad_Combo_ID|
| --|--|
| B2| 4 |
一般来说,我所尝试的一切似乎要么是不必要的复杂和缓慢,要么是在上面的例子中标记了A1和C3。

shyt4zoc

shyt4zoc1#

根据我对你的问题的理解,你想做这样的事情:

WITH user_items AS
  (SELECT 
    username,
    LISTAGG(item,',') AS item_list
  FROM attributes
  GROUP BY username)
SELECT 
  ROW_NUMBER() 
    OVER(ORDER BY u.username) AS Bad_Combo_User_ID,
  u.username, 
  c.ComboID
FROM user_items u
INNER JOIN combinations c ON
  INSTR(u.item_list, c.item1) > 0
  AND INSTR(u.item_list, c.item2) > 0;

字符串
我根据您的示例数据创建了一个sample fiddle,并为用户D4和E5扩展了一些数据。
我认为结果是正确的,符合你的要求。
此查询如何工作?
首先,我们使用CTE构建一个逗号分隔的列表,其中包含属性表中每个用户出现的所有项。
然后,我们使用主查询将项目列表与组合表中的项目进行比较。在INNER JOINON子句中,我们说同一行中组合表中的两个项目必须出现在用户的“项目列表”中。如果是这种情况,我们将此用户添加到结果中。
所以结果只会显示那些项目组合无效的用户。ROW_NUMBER只是创建一个按用户名排序的递增数字。当我读到你的问题时,这就是你想要做的。
即使我理解错了什么,答案不是100%你想做的,我认为这应该是一个足够的帮助你指向正确的方向.请让我们知道.

v64noz0r

v64noz0r2#

尝试这个简单的sql,其中HAVING子句定义了每个用户是否有来自列ITEM_1和ITEM_2的组合-这是一个糟糕的组合。

--  M a i n    S Q L :
Select      a.USER_ID, c.ID "BAD_COMBO_ID"
From        combos c
Left Join   attribs a ON(   a.ITEM IN( c.ITEM_1, c.ITEM_2 ) )
Group By  a.USER_ID, c.ID
Having    Count(Distinct  Case  When a.ITEM = c.ITEM_1 Then 1
                                When a.ITEM = c.ITEM_2 Then 2
                          End) > 1

字符串
...根据提供的样本数据...

WITH    --  S a m p l e    D a t a :
    combos (ID, ITEM_1, ITEM_2) AS
        (   Select 1, 'Ice Cream', 'Hot Sauce' From Dual Union All
            Select 2, 'Asparagus', 'Chocolate' From Dual Union All
            Select 3, 'Peanut Butter', 'Steak' From Dual Union All
            Select 4, 'Asparagus', 'Ice Cream' From Dual 
        ), 
    attribs (ID, USER_ID, ITEM) AS
        (   Select 1, 'A1', 'Ice Cream' From Dual Union All 
            Select 2, 'B2', 'Asparagus' From Dual Union All 
            Select 3, 'A1', 'Chocolate' From Dual Union All 
            Select 4, 'B2', 'Ice Cream' From Dual Union All 
            Select 5, 'C3', 'Steak' From Dual Union All 
            Select 6, 'C3', 'Ice Cream' From Dual Union All 
            Select 7, 'C3', 'Chocolate' From Dual 
    )


.结果:

--      R e s u l t :
--  USER_ID BAD_COMBO_ID
--  ------- ------------
--  B2            4


另外,如果您需要查看组合,只需添加c.ITEM_1||‘--’||c.ITEM_2“COMBO”到选择列表,c.ITEM_1、c.ITEM_2到Group By子句。结果应该是:

--      R e s u l t :
--  USER_ID BAD_COMBO_ID COMBO
--  ------- ------------ ---------------------------
--  B2            4      Asparagus-Ice Cream

px9o7tmv

px9o7tmv3#

由于你有固定的组合属性集,你可以使用类似于这个问题的方法:SQL query: Simulating an "AND" over several rows instead of sub-querying
使用unpivot将列转换为行,以列表的形式表示项目,并执行left join以查找匹配的项目。最后的常数2是组合的项目数(即源表中的列数)。

with combos_unpivot as (
  select *
  from combos
  unpivot (
    item for num in (item1 as 1, item2 as 2)
  )
)

select
  u.user_,
  c.comboid
from users u
  left join combos_unpivot c
    on u.item = c.item
group by u.user_, c.comboid
having count(c.item) = 2

字符串
对于您的示例数据,

create table combos(ComboID, Item1, Item2) as
  select 1, 'Ice Cream', 'Hot Sauce' from dual union all
  select 2, 'Asparagus', 'Chocolate' from dual union all
  select 3, 'Peanut Butter', 'Steak' from dual union all
  select 4, 'Asparagus', 'Ice Cream' from dual
create table users (UserAttributeID, User_, Item) as
  select 1, 'A1', 'Ice Cream' from dual union all
  select 2, 'B2', 'Asparagus' from dual union all
  select 3, 'A1', 'Chocolate' from dual union all
  select 4, 'B2', 'Ice Cream' from dual union all
  select 5, 'C3', 'Steak' from dual union all
  select 6, 'C3', 'Ice Cream' from dual union all
  select 7, 'C3', 'Chocolate' from dual

的数据
它返回
| 用户_|COMBOID|
| --|--|
| B2| 4 |
fiddle
请注意,它的伸缩性很好,因为有一个没有函数的等价连接,最有可能导致散列连接。
如果您想缩放此组合以获得无限的组合大小,并将组合项存储为行而不是列,那么它也很容易适应:在CTE中计算组合大小,并在having中使用该组合大小而不是常量。

with combos_unpivot as (
  select ComboID, Item, count(*) over(partition by ComboID) as combo_size
  from combos_vertical
)

select
  u.user_,
  c.comboid
from users u
  left join combos_unpivot c
    on u.item = c.item
group by u.user_, c.comboid
having count(c.item) = max(c.combo_size)


对于此添加的示例数据:

create table combos_vertical(ComboID, itemno, Item) as
  select 1, 1, 'Ice Cream'  from dual union all
  select 1, 1, 'Hot Sauce' from dual union all
  select 2, 1, 'Asparagus' from dual union all
  select 2, 2, 'Chocolate' from dual union all
  select 3, 1, 'Peanut Butter' from dual union all
  select 3, 2, 'Steak' from dual union all
  select 4, 1, 'Asparagus' from dual union all
  select 4, 2, 'Ice Cream' from dual union all
  select 5, 1, 'Steak' from dual union all
  select 5, 2, 'Ice Cream' from dual union all
  select 5, 3, 'Chocolate' from dual


它将返回
| 用户_|COMBOID|
| --|--|
| B2| 4 |
| C3| 5 |
fiddle

相关问题