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
好的,所以我已经为其他人的查询做了很多挖掘和尝试各种片段和解决方案,但我似乎无法在这里获得任何牵引力。另外,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 |