Я пытаюсь присвоить идентификатор аналогичным группам записей на основе критериев или в Redshift.
С данными из устаревшей системы я пытаюсь сопоставить всех клиентовкоторые имеют те же business_name
или first_name
+ last_name
и присваивают этим записям временную grouping_id
до дальнейшей обработки.
Упрощенная версия таблицы и данных
-- used in part of the example...
CREATE OR REPLACE FUNCTION public.fn_uuid()
RETURNS character varying AS
' import uuid
return uuid.uuid4().__str__()
'
LANGUAGE plpythonu VOLATILE;
create table temp_customers (source_record_id bigint identity(1,1) not null, business_name text, first_name text, last_name text);
insert into temp_customers (business_name, first_name, last_name)
values
('Bat Man', 'Bat', 'Man'),
('Dark Knight', 'Bat', 'Man'),
('Bat Man', 'Bat', 'Man'),
('Dark Knight', 'Bat', 'Man'),
('Dark Knight', 'Bruce', 'Wayne'),
('Super Man', 'Super', 'Man'),
('Spider Man', 'Spider', 'Man'),
('Spiderman', 'Spider', 'Man');
select * from temp_customers order by last_name, first_name, business_name
, что приводит к этой таблице.
source_record_id|business_name|first_name|last_name|
----------------|-------------|----------|---------|
1|Bat Man |Bat |Man |
3|Bat Man |Bat |Man |
2|Dark Knight |Bat |Man |
4|Dark Knight |Bat |Man |
5|Dark Knight |Bruce |Wayne |
7|Spider Man |Spider |Man |
8|Spiderman |Spider |Man |
6|Super Man |Super |Man |
ПРИМЕЧАНИЕ: отредактировано с последней попыткой 2019-04-22
Мой последний подходбыло взять сумму того, что совпало по номеру строки и использовать это в качестве базовой линии для сопоставления.Когда сумма строк по номеру строки была равна 2, присвоение group_id было сброшено.
Первая часть назначения идентификатора группы работает правильно для первой записи.Я пытаюсь выяснить, как назначить последующие нулевые значения для match_id
в качестве значения предыдущего match_id
.Я думал, что мог бы использовать coalesce
+ lag
, чтобы получить последнее заполненное значение, но запрос не выполняется, потому что "Недопустимая операция: не следует указывать предложение Frame для оконной функции lag;"Снятие ROWS BETWEEN...
не решило проблему.Текущая версия с first_value
, похоже, не возвращается к первому ряду.Моя попытка сделать это с вложенным объединением привела только к одной дополнительной записи, которая была обновлена.
WITH matched_records AS (
SELECT source_record_id, business_name, last_name, first_name,
ROW_NUMBER() OVER (PARTITION BY business_name ORDER BY business_name DESC) AS bname_match,
ROW_NUMBER() OVER (PARTITION BY last_name, first_name ORDER BY last_name DESC, first_name DESC) AS fl_match
FROM temp_customers
WHERE (business_name = business_name OR (last_name = last_name AND first_name = first_name))
GROUP BY business_name, first_name, last_name, source_record_id
),
scored_records AS (
SELECT *, (bname_match + fl_match) AS match_score
FROM matched_records
),
part_grouped_records AS (
SELECT *, CASE
WHEN match_score = 2 THEN fn_uuid()
END AS match_id
FROM scored_records
ORDER BY business_name,
last_name,
first_name,
bname_match,
fl_match,
match_score
),
full_grouped_records AS (
SELECT source_record_id, business_name, last_name, first_name, bname_match, fl_match, match_score,
COALESCE(match_id, FIRST_VALUE(match_id IGNORE nulls) OVER (PARTITION BY business_name, last_name, first_name, bname_match, fl_match, match_score ORDER BY business_name, last_name, first_name, bname_match, fl_match, match_score, match_id ROWS BETWEEN unbounded preceding AND CURRENT ROW) ) AS match_id
FROM part_grouped_records
)
SELECT *
FROM full_grouped_records
ORDER BY business_name,
last_name,
first_name,
bname_match,
fl_match,
match_score
, которая приводит к следующим результатам
source_record_id|business_name|last_name|first_name|bname_match|fl_match|match_score|match_id |
----------------|-------------|---------|----------|-----------|--------|-----------|------------------------------------|
1|Bat Man |Man |Bat | 1| 1| 2|424f30d3-4f43-4c1d-8658-344853857b8b|
3|Bat Man |Man |Bat | 2| 2| 4| |
2|Dark Knight |Man |Bat | 1| 3| 4| |
4|Dark Knight |Man |Bat | 2| 4| 6| |
5|Dark Knight |Wayne |Bruce | 3| 1| 4| |
7|Spider Man |Man |Spider | 1| 1| 2|88691e14-4e86-4547-84a5-6d071d86e23b|
8|Spiderman |Man |Spider | 1| 2| 3| |
6|Super Man |Man |Super | 1| 1| 2|92b7c51a-c463-47a6-b25d-8820bb009565|
Но я ищу этоустановка любого match_id, который был нулевым, для ранее заполненного ненулевого значения.
source_record_id|business_name|last_name|first_name|bname_match|fl_match|match_score|match_id |
----------------|-------------|---------|----------|-----------|--------|-----------|------------------------------------|
1|Bat Man |Man |Bat | 1| 1| 2|424f30d3-4f43-4c1d-8658-344853857b8b|
3|Bat Man |Man |Bat | 2| 2| 4|424f30d3-4f43-4c1d-8658-344853857b8b|
2|Dark Knight |Man |Bat | 1| 3| 4|424f30d3-4f43-4c1d-8658-344853857b8b|
4|Dark Knight |Man |Bat | 2| 4| 6|424f30d3-4f43-4c1d-8658-344853857b8b|
5|Dark Knight |Wayne |Bruce | 3| 1| 4|424f30d3-4f43-4c1d-8658-344853857b8b|
7|Spider Man |Man |Spider | 1| 1| 2|88691e14-4e86-4547-84a5-6d071d86e23b|
8|Spiderman |Man |Spider | 1| 2| 3|88691e14-4e86-4547-84a5-6d071d86e23b|
6|Super Man |Man |Super | 1| 1| 2|92b7c51a-c463-47a6-b25d-8820bb009565|
Любая помощь или совет очень важны!
РЕДАКТИРОВАТЬ - РЕШЕНИЕ
Он работает после нескольких настроек COALESCE
WITH matched_records AS (
SELECT source_record_id, business_name, last_name, first_name,
ROW_NUMBER() OVER (PARTITION BY business_name ORDER BY business_name DESC) AS bname_match,
ROW_NUMBER() OVER (PARTITION BY last_name, first_name ORDER BY last_name DESC, first_name DESC) AS fl_match
FROM temp_customers
WHERE (business_name = business_name OR (last_name = last_name AND first_name = first_name))
GROUP BY business_name, first_name, last_name, source_record_id
),
scored_records AS (
SELECT *, (bname_match + fl_match) AS match_score
FROM matched_records
),
part_grouped_records AS (
SELECT *, CASE
WHEN match_score = 2 THEN fn_uuid()
END AS match_id
FROM scored_records
ORDER BY business_name,
last_name,
first_name,
bname_match,
fl_match,
match_score
)
SELECT source_record_id, business_name, last_name, first_name, bname_match, fl_match, match_score,
COALESCE(match_id, lag(match_id IGNORE nulls) OVER (ORDER BY business_name, last_name, first_name, bname_match, fl_match, match_score) ) AS match_id
FROM part_grouped_records
ORDER BY business_name,
last_name,
first_name,
bname_match,
fl_match,
match_score
source_record_id|business_name|last_name|first_name|bname_match|fl_match|match_score|match_id |
----------------|-------------|---------|----------|-----------|--------|-----------|------------------------------------|
1|Bat Man |Man |Bat | 1| 1| 2|1e57ef76-7425-40c9-af1d-8ac1054f1bd7|
3|Bat Man |Man |Bat | 2| 2| 4|1e57ef76-7425-40c9-af1d-8ac1054f1bd7|
2|Dark Knight |Man |Bat | 1| 3| 4|1e57ef76-7425-40c9-af1d-8ac1054f1bd7|
4|Dark Knight |Man |Bat | 2| 4| 6|1e57ef76-7425-40c9-af1d-8ac1054f1bd7|
5|Dark Knight |Wayne |Bruce | 3| 1| 4|1e57ef76-7425-40c9-af1d-8ac1054f1bd7|
7|Spider Man |Man |Spider | 1| 1| 2|3fc40421-4fb1-4348-a294-a0ba899e611b|
8|Spiderman |Man |Spider | 1| 2| 3|3fc40421-4fb1-4348-a294-a0ba899e611b|
6|Super Man |Man |Super | 1| 1| 2|82bff96e-81d2-4716-8632-81c117633126|
РЕДАКТИРОВАТЬ # 3 - ФИНАЛЬНЫЙ
Это окончательное решение, которое я закончилс.В предыдущем решении была проблема с использованием row_number
для большого набора данных, поскольку имя совпадало и получало число больше 2, которое я использовал для увеличения счетчика.
Это решение просто ищет критерии (бизнес-имя -или- первое + последнее совпадение) и помечает запись как 0, чтобы пометить новый прогон и последующие совпадения как 1 (match_score).Временный идентификатор добавляется в score_identified_records
ко всем значениям match_score, равным 0. Последующий CTE group_matched_records
применяет группировку с coalesce
+ lag
для получения соответствующей группы.Вы можете продвинуть логику для score_identified_records
в match_scored_records
и получить те же результаты с одним меньшим шагом.Я нашел match_score
полезным для отладки.
WITH match_scored_records AS (
SELECT source_record_id,
business_name,
last_name,
first_name,
CASE WHEN lag(business_name) OVER (ORDER BY business_name, last_name, first_name) = business_name OR
(
lag(first_name) OVER (ORDER BY business_name, last_name, first_name) = first_name AND
lag(last_name) OVER (ORDER BY business_name, last_name, first_name) = last_name
) THEN 1
ELSE 0
END AS match_score
FROM temp_customers
WHERE (business_name = business_name OR (last_name = last_name AND first_name = first_name))
GROUP BY business_name,
first_name,
last_name,
source_record_id
),
score_identified_records AS (
SELECT *,
CASE WHEN match_score = 0 THEN fn_uuid()
END AS match_id
FROM match_scored_records
ORDER BY business_name,
last_name,
first_name,
match_score ASC
),
grouped_matched_records AS (
SELECT source_record_id,
business_name,
last_name,
first_name,
match_score,
COALESCE(match_id, lag(match_id IGNORE nulls) OVER (ORDER BY business_name, last_name, first_name, match_score ASC)) AS match_id
FROM score_identified_records
ORDER BY business_name,
last_name,
first_name,
match_score ASC
)
SELECT *
FROM grouped_matched_records
Результаты:
source_record_id|business_name|last_name|first_name|match_score|match_id |
----------------|-------------|---------|----------|-----------|------------------------------------|
3|Bat Man |Man |Bat | 0|b84929f8-777c-4ec4-ae29-87cad4e0f57e|
1|Bat Man |Man |Bat | 1|b84929f8-777c-4ec4-ae29-87cad4e0f57e|
2|Dark Knight |Man |Bat | 1|b84929f8-777c-4ec4-ae29-87cad4e0f57e|
4|Dark Knight |Man |Bat | 1|b84929f8-777c-4ec4-ae29-87cad4e0f57e|
5|Dark Knight |Wayne |Bruce | 1|b84929f8-777c-4ec4-ae29-87cad4e0f57e|
7|Spider Man |Man |Spider | 0|549d2fa3-9ec5-4728-b120-c00c1d866811|
8|Spiderman |Man |Spider | 1|549d2fa3-9ec5-4728-b120-c00c1d866811|
6|Super Man |Man |Super | 0|19f66f27-a187-4f3c-954f-5de260b85153|