Snowflake SQL - 在变量 VARCHAR 范围内查找缺失值,具有多个 table 连接

Snowflake SQL - Find missing values within a variable VARCHAR range, with multiple table join

好的,所以我已经为其他人的查询做了很多挖掘和尝试各种片段和解决方案,但我似乎无法在这里获得任何牵引力。另外,sql 2 周前才开始尝试,所以请原谅初学者...

我有一个 ITEMS table ITEM_ID 和 GROUP_ID,以及 GRP table GROUP_ID 和 GROUP_NAME

有时在最小值和最大值内缺少 ITEM_ID(不幸的是,并非所有组都从 1 开始)并且它们是 VARCHAR

我希望能够通过 GROUP_NAME 搜索丢失的 ITEM_ID 的

我一直在尝试使用:

with nums as (
SELECT 
seq4()+1 as id
  from table(generator(rowcount => 10)) 
)

SELECT nums.id

要获得 1 到任意多行的列表,但需要这是 ITEM_ID 的最小值和最大值。我试图放入一个 CAST 或什至只是一个 min(item.ITEM_ID) 但我 运行 遇到了问题,因为 ITEMS table 已经很大,因此按 GROUP_NAME 排序

很抱歉我没有很多代码示例,因为我几乎无法得到任何东西 运行。但这是我加入 ITEMS 和 GRP tables 以按名称搜索的方式:

SELECT
    item.NAME, item.ITEM_ID, grp.NAME
FROM
    API_ITEMS item
    LEFT JOIN API_GROUPS grp ON item.group_id = grp.id
WHERE
    grp.NAME = 'silverware'
GROUP by item.ITEM_ID ASC

我认为很多这只是因为我对 sql 超级绿色,但基本上我正在尝试搜索 GROUP_NAME 的 ITEMS 以找到丢失的 ITEM_IDS

在我的 API_ITEMS table 中,我有所有组的所有项目,我想仅按 grp.NAME 进行过滤,并找出缺少的 ITEM_ID最小值(item.ITEM_ID),最大值(item.ITEM_ID)。不确定我是否需要为 min/max CAST as INT,或者 varchar 在这里是否同样有效。我在想,如果我可以将它加入一个从最小值到最大值的 seq4(),我可以在有 seq4() 条目但没有 ITEM_ID 条目

的地方找到空条目

1 这个例子是一个连接 table 我有

ITEM_ID   grp.NAME
1         silverware
2         silverware
3         silverware
4         silverware
5000      silverware

我找到了一个 gap 脚本,它会输出 gap 从 5 开始,到 4999 结束,但这对我的所有 grp.NAME

都不起作用

在这个例子中,我的想法是我可以创建一个 seq4() as nums table 5000 项。在 item.ITEM_ID = nums.ID 上加入项目 table 以获得

nums.ID      ITEM_ID
1            1
2            2
3            3
4            4
5            null
6            null
...
5000         5000

我想要一个缺少每个 ITEM.ID 的输出,例如

MISSING_ITEM_ID
5
6
7
...
4999

感谢任何愿意拿起这个,握住我的手,帮助我的人。

我正在使用雪花,我无法访问 Tally tables...

不确定这是否正是您要查找的内容,但您可以使用统一函数为随机函数提供最小和最大阈值。在此示例中,对于创建的 10 行中的每一行,您将获得 MIN 1 和 MAX 10。

 SELECT
   uniform(1, 10, random(1)) as ITEM_ID
from table(generator(rowcount=>10));

统一文档: https://docs.snowflake.com/en/sql-reference/functions/uniform.html

所以按照你的例子,我做了一些 CTE(可能是 tables,但它们是可以互换的),选择了较小的数字范围,这样输出就不会太长

with items(item_id, item_name, group_id ) as (
    select * from values
    (1, 'item1', 100),
    (2, 'item2', 100),
    (3, 'item3', 100),
    (4, 'item4', 100),
    (9, 'item31', 100),
    (1, 'item1-101', 101)
), groups(group_id, name) as (
    select * from values
    (100, 'silverware'),
    (101, 'leadware')
)

并加入这些以找到 'silverware' 项目,就像您拥有的一样

select i.item_id,
    i.item_name,
    g.name
from items as i
join groups as g
    on i.group_id = g.group_id
where g.name = 'silverware'    

给出:

ITEM_ID ITEM_NAME NAME
1 item1 silverware
2 item2 silverware
3 item3 silverware
4 item4 silverware
9 item31 silverware

现在你想要一个数字范围内的 CTE,为此你必须使用 ROW_NUMBER 函数,因为 SEQx() 可以在输出中有间隙,如果你只想要向上的不同数字 SEQ 是更快,但如果你想没有洞,SEQ会随机烧你。

所以让我们将 nums CTE 交换为 ROW_NUMBER,然后选择一个比您拥有的任何范围都大的大数字。在现实世界中,我会制作一个包含 100 万行的 table,然后直接使用它。

with nums as (
    SELECT 
        row_number()over(order by null) as id
    from table(generator(rowcount => 5000)) 
)

所以现在我们在 nums 中有了大量的 id 和我们想要的数据。

  • 所以现在我们必须要做一些事情,将范围加入我们的数据,并修剪超出范围的值..
  • 找出差距

所以有了这些:

with nums as (
    SELECT 
        row_number()over(order by null) as id
    from table(generator(rowcount => 5000)) 
), wanted_data as (
    select i.item_id,
        i.item_name,
        i.group_id,
        g.name
    from items as i
    join groups as g
        on i.group_id = g.group_id
    where g.name = 'silverware'   
), ranges as (
    select group_id,
        min(item_id) as min_id,
        max(item_id) as max_id
    from wanted_data
    group by 1
)

这里显示的是range join,还有left join的前半部分

select 
    n.id,
    r.group_id,
    w.*
from nums as n
join ranges as r
    on n.id between r.min_id and r.max_id
left join wanted_data as w
    on w.item_id = n.id
ID GROUP_ID ITEM_ID ITEM_NAME GROUP_ID_2 NAME
1 100 1 item1 100 silverware
2 100 2 item2 100 silverware
3 100 3 item3 100 silverware
4 100 4 item4 100 silverware
5 100 null null null null
6 100 null null null null
7 100 null null null null
8 100 null null null null
9 100 9 item31 100 silverware

现在我们可以通过添加到末尾来过滤掉未命中的左连接:

where w.item_id is null
ID GROUP_ID ITEM_ID ITEM_NAME GROUP_ID_2 NAME
5 100 null null null null
6 100 null null null null
7 100 null null null null
8 100 null null null null

所以我们不需要 select 那些失败的加入 w.* 值,但我们目前缺少组名。此时,您可以将 re-join 分配给 table 组(这就是我倾向于在大型工作流中做事以避免在转换阶段携带太多价值的方式)。还是随身携带吧

因此所有 SQL 在一起:

with items(item_id, item_name, group_id ) as (
    select * from values
    (1, 'item1', 100),
    (2, 'item2', 100),
    (3, 'item3', 100),
    (4, 'item4', 100),
    (9, 'item31', 100),
    (1, 'item1-101', 101)
), groups(group_id, name) as (
    select * from values
    (100, 'silverware'),
    (101, 'leadware')
), nums as (
    SELECT 
        row_number()over(order by null) as id
    from table(generator(rowcount => 5000)) 
), wanted_data as (
    select i.item_id,
        i.item_name,
        i.group_id,
        g.name
    from items as i
    join groups as g
        on i.group_id = g.group_id
    where g.name = 'silverware'   
), ranges as (
    select group_id,
        name as group_name,
        min(item_id) as min_id,
        max(item_id) as max_id
    from wanted_data
    group by 1,2
)
select 
    n.id,
    r.group_id,
    r.group_name
from nums as n
join ranges as r
    on n.id between r.min_id and r.max_id
left join wanted_data as w
    on w.item_id = n.id
where w.item_id is null

给出:

ID GROUP_ID GROUP_NAME
5 100 silverware
6 100 silverware
7 100 silverware
8 100 silverware

其他范围方式:

现在如果你的 id 的数字 space 非常高,有一个巨大的数字 table 会很恶心。

with items(item_id, item_name, group_id ) as (
    select * from values
    (1000001, 'item1', 100),
    (1000002, 'item2', 100),
    (1000003, 'item3', 100),
    (1000004, 'item4', 100),
    (1000009, 'item31', 100),
    (2000001, 'item1-101', 101)
)

然后更改 nums 以生成 0

), nums as (
    SELECT 
        row_number()over(order by null)-1 as id
    from table(generator(rowcount => 5000)) 
)

您可以使用较小的范围 table,并且只使用相对数学:

select 
    n.id+r.min_id as id,
    r.group_id,
    r.group_name
from nums as n
join ranges as r
    on n.id <= r.span
left join wanted_data as w
    on w.item_id = n.id+r.min_id
where w.item_id is null

获得:

ID GROUP_ID GROUP_NAME
1000005 100 silverware
1000006 100 silverware
1000007 100 silverware
1000008 100 silverware