как определить строки с одинаковыми значениями в полях / столбцах одной строки - PullRequest
0 голосов
/ 14 мая 2018

В таблице я хочу найти строки, в которых как минимум 2 поля (столбца) имеют повторяющееся значение «не ноль». Универсальное решение SQL будет предпочтительнее, потому что оно может использоваться в любой БД. Если не так, Oracle и SQL Server - мои целевые БД. Как пример

ID    COL1    COL2    COL3    COL4
1      11     11       11      44
2      11     22       33      44
3      11     null     33      33
4      11     null     null    44

должен вернуть следующие строки

ID    COL1    COL2    COL3    COL4
1      11     11       11      44
3      11     null     33      33

В первой строке 3 поля с повторяющимся значением 11, а в другой строке с col3 и col4 дублированное значение 33

Ответы [ 4 ]

0 голосов
/ 14 мая 2018

Для SQL Server я бы использовал оператор APPLY, чтобы сделать это:

select * 
from (select *, (select COUNT(*) from (values (Col1), (Col2),.. (ColN))t(ids)) TotalCols,
                (select COUNT(distinct ids) from (values (Col1), (Col2),.. (ColN))t(ids)) DistinctCols
      from table t
    ) t
where TotalIds <> DistinctCols;
0 голосов
/ 14 мая 2018

Вы можете сделать это в Oracle, используя UNPIVOT:

SQL Fiddle

Настройка схемы Oracle 11g R2 :

CREATE TABLE table_name ( ID, COL1, COL2, COL3, COL4 ) As
SELECT 1,      11,     11,       11,      44 FROM DUAL UNION ALL
SELECT 2,      11,     22,       33,      44 FROM DUAL UNION ALL
SELECT 3,      11,     null,     33,      33 FROM DUAL UNION ALL
SELECT 4,      11,     null,     null,    44 FROM DUAL;

Запрос 1 :

SELECT *
FROM   table_name
WHERE  id IN (
  SELECT id
  FROM   table_name
  UNPIVOT ( value FOR key IN ( COL1, COL2, COL3, COL4 ) )
  GROUP BY id, value
  HAVING COUNT( DISTINCT key ) > 1
)

Результаты

| ID | COL1 |   COL2 | COL3 | COL4 |
|----|------|--------|------|------|
|  1 |   11 |     11 |   11 |   44 |
|  3 |   11 | (null) |   33 |   33 |

Если вы хотите сопоставить на NULL, просто используйте UNPIVOT INCLUDE NULLS.

И SQL Server, с почти таким же кодом (просто нужен псевдоним на UNPIVOT):

SQL Fiddle

Запрос 1 :

SELECT *
FROM   table_name
WHERE  id IN (
  SELECT id
  FROM   table_name
  UNPIVOT ( value FOR name IN ( COL1, COL2, COL3, COL4 ) ) AS u
  GROUP BY id, value
  HAVING COUNT( DISTINCT name ) > 1
)

Результаты :

| ID | COL1 |   COL2 | COL3 | COL4 |
|----|------|--------|------|------|
|  1 |   11 |     11 |   11 |   44 |
|  3 |   11 | (null) |   33 |   33 |

Обновление

Вы также можете сгенерировать запрос грубой силы, используя таблицу словаря *_TAB_COLUMN в Oracle (вероятно, в SQL-сервере есть эквивалент):

SELECT 'SELECT * FROM TABLE_NAME WHERE ('
       || LISTAGG(
            '"' || PRIOR COLUMN_NAME || '" = "' || COLUMN_NAME || '"',
            ' OR '
          ) WITHIN GROUP ( ORDER BY ROWNUM )
          || ')' AS query
FROM   USER_TAB_COLUMNS
WHERE  TABLE_NAME = 'TABLE_NAME'
AND    COLUMN_NAME LIKE 'COL%'
AND    LEVEL = 2
START WITH COLUMN_NAME LIKE 'COL%'
CONNECT BY PRIOR COLUMN_ID < COLUMN_ID;

Какие выходы:

SELECT * FROM TABLE_NAME WHERE ("COL1" = "COL2" OR "COL1" = "COL3" OR "COL1" = "COL4" OR "COL2" = "COL3" OR "COL2" = "COL4" OR "COL3" = "COL4")
0 голосов
/ 14 мая 2018

Решение без жестко закодированных имен столбцов (Sql Server).Допустим, наш стол [#test].Тогда наш запрос:

;with [temp] as (
    select
         [id]           =   id
        ,[col_name1]    =   [c1].[value]('local-name(.)',   'nvarchar(256)')
        ,[col_value1]   =   [c1].[value]('.',               'nvarchar(256)')
        ,[col_name2]    =   [c2].[value]('local-name(.)',   'nvarchar(256)')
        ,[col_value2]   =   [c2].[value]('.',               'nvarchar(256)')    
    from 
        [#test] as  [t]
    cross apply
        (
            select [data] = convert(xml, (select [t].* for xml path('row') ))
        )       as  [x]
    cross apply
        [x].[data].[nodes]('row/*') as [t1]([c1])
    cross apply
        [x].[data].[nodes]('row/*') as [t2]([c2])
)
,[ids] as (
    select 
        [id]
    from 
        [temp]
    where
            ([col_name1]    <>  [col_name2] )
        and ([col_value1]   =   [col_value2])
    group by
         [id]
)
select 
    *
from
    [#test] as  [t]
inner join
    [ids]   as  [i]
on
        [t].[id] = [i].[id];

Полный запрос можно найти: https://pastebin.com/jUG5r41c

0 голосов
/ 14 мая 2018

Метод грубой силы:

select t.*
from t
where (col1 = col2 or col1 = col3 or col1 = col4 or
       col2 = col3 or col2 = col4 or col3 = col4
      ) or
      (col1 is null and (col2 is null or col3 is null or col4 is null) or
       col2 is null and (col3 is null or col4 is null) or
       col3 is null and col4 is null
      )

Это будет работать в любой базе данных.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...