У меня есть таблица company
с 60 столбцами. Цель состоит в том, чтобы создать инструмент для поиска, сравнения и устранения дубликатов в этой таблице.
Пример: я нашел 2 компании, которые потенциально являются одинаковыми, но мне нужно знать, какие значения (столбцы) отличаются в этих 2 строках, чтобы продолжить.
Я думаю, что можно сравнить столбец по столбцу x 60, но я ищу более простое и универсальное решение.
Что-то типа:
SELECT * FROM company where co_id=22
SHOW DIFFERENCE
SELECT * FROM company where co_id=33
В результате должны получиться разные имена столбцов.
2 ответа
Для этого вы можете использовать промежуточное представление строк с ключом / значением, с функциями JSON или альтернативно с hstore
(сейчас представляет только исторический интерес). JSON встроен во все достаточно свежие версии PostgreSQL, тогда как hstore должен быть установлен в базе данных с помощью CREATE EXTENSION.
Демо:
CREATE TABLE table1 (id int primary key, t1 text, t2 text, t3 text);
Давайте вставим две строки, которые отличаются первичным ключом, и еще один столбец (t3
).
INSERT INTO table1 VALUES
(1,'foo','bar','baz'),
(2,'foo','bar','biz');
Решение с json
Сначала получаем представление строк с исходным номером строки в виде ключа / значения, затем мы объединяем строки в пары на основе их исходных номеров строк и отфильтровываем строки с тем же столбцом «значение»
WITH rowcols AS (
select rn, key, value
from (select row_number() over () as rn,
row_to_json(table1.*) as r from table1) AS s
cross join lateral json_each_text(s.r)
)
select r1.key from rowcols r1 join rowcols r2
on (r1.rn=r2.rn-1 and r1.key = r2.key)
where r1.value <> r2.value;
Результат образца:
key ----- id t3
Решение с hstore
SELECT skeys(h1-h2) from
(select hstore(t.*) as h1 from table1 t where id=1) h1
CROSS JOIN
(select hstore(t.*) as h2 from table1 t where id=2) h2;
h1-h2
вычисляет разницу ключ за ключом, а skeys()
выводит результат в виде набора.
Результат:
skeys ------- id t3
Список выбора может быть уточнен с помощью skeys((h1-h2)-'id'::text)
, чтобы всегда удалять id
, который, как первичный ключ, очевидно, всегда будет различаться между строками.
Вот хранимая процедура, которая поможет вам разобраться ...
Хотя это должно работать «как есть», в нем нет проверки ошибок, которую вы должны добавить.
Он получает все столбцы в таблице и перебирает их. Разница в том, что количество отдельных элементов больше одного. Также вывод:
- Подсчет количества отличий
- Сообщения для каждого столбца, где есть разница
Было бы более полезно вернуть набор строк с различиями в столбцах. В любом случае, удачи!
Применение:
SELECT showdifference('public','company','co_id',22,33)
CREATE OR REPLACE FUNCTION showdifference(p_schema text, p_tablename text,p_idcolumn text,p_firstid integer, p_secondid integer)
RETURNS INTEGER AS
$BODY$
DECLARE
l_diffcount INTEGER;
l_column text;
l_dupcount integer;
column_cursor CURSOR FOR select column_name from information_schema.columns where table_name = p_tablename and table_schema = p_schema and column_name <> p_idcolumn;
BEGIN
-- need error checking here, to ensure the table and schema exist and the columns exist
-- Should also check that the records ids exist.
-- Should also check that the column type of the id field is integer
-- Set the number of differences to zero.
l_diffcount := 0;
-- use a cursor to iterate over the columns found in information_schema.columns
-- open the cursor
OPEN column_cursor;
LOOP
FETCH column_cursor INTO l_column;
EXIT WHEN NOT FOUND;
-- build a query to see if there is a difference between the columns. If there is raise a notice
EXECUTE 'select count(distinct ' || quote_ident(l_column) || ' ) from ' || quote_ident(p_schema) || '.' || quote_ident(p_tablename) || ' where ' || quote_ident(p_idcolumn) || ' in ('|| p_firstid || ',' || p_secondid ||')'
INTO l_dupcount;
IF l_dupcount > 1 THEN
-- increment the counter
l_diffcount := l_diffcount +1;
RAISE NOTICE '% has % differences', l_column, l_dupcount ; -- for "real" you might want to return a rowset and could do something here
END IF;
END LOOP;
-- close the cursor
CLOSE column_cursor;
RETURN l_diffcount;
END;
$BODY$
LANGUAGE plpgsql VOLATILE STRICT
COST 100;
Похожие вопросы
Связанные вопросы
Новые вопросы
postgresql
PostgreSQL — это система управления реляционными базами данных (RDBMS) с открытым исходным кодом, доступная для всех основных платформ, включая Linux, UNIX, Windows и OS X. Задавая вопросы, указывайте свою версию Postgres. Обратитесь к dba.stackexchange.com для вопросов, касающихся администрирования или дополнительных функций.