ВЫБРАТЬ без дубликатов, если не перебиваются другими значениями - PullRequest
0 голосов
/ 13 января 2020

Учитывая следующие данные:

name | temp
-----------
hoi  | 15
hoi  | 15
hoi  | 16
hoi  | 15
hej  | 13
hoi  | 13

Я хотел бы выбрать данные в данных двух столбцах без дубликатов, однако я хочу сохранить дубликаты, которые являются дубликатами, если они были прерваны другим значением:

name | temp
-----------
hoi  | 15 // selected
hoi  | 15 // ignored duplicate
hoi  | 15 // ignored duplicate
hoi  | 16 // selected
hoi  | 15 // selected because while not being unique it follows a different value
hoi  | 15 // ignored duplicate
hej  | 13 // selected
hoi  | 13 // selected
hoi  | 13 // ignored duplicate
hoi  | 14 // selected
hoi  | 13 // selected because while not being unique it follows a different value

Этот вопрос было трудно сформулировать для меня, учитывая, что Engli sh не является моим родным языком, не стесняйтесь редактировать вопрос или просить разъяснений.

Редактировать: Существует Поле id и поле даты и времени.

Редактировать 2: Я использую mySQL 5.7

Ответы [ 5 ]

2 голосов
/ 13 января 2020

Generi c Решение

Вы можете использовать следующий запрос для выполнения в любой СУБД:

select nd.*
from dedup nd
inner join (
  -- find the previous id for each id
  select id, (select max(id) from dedup where id < o.id) prev_id
  from dedup o
) id_to_prev on id_to_prev.id = nd.id
-- join with the prev row to check for dups
left join dedup d on d.id = id_to_prev.prev_id 
                     and d.name = nd.name
                     and d.temp = nd.temp 
where d.id is null -- if no prev row found with same name+temp, include this row
order by nd.id

SQL Fiddle : http://sqlfiddle.com/#! 9 / 0584ca3 / 9

2 голосов
/ 13 января 2020

Поскольку вы используете MySQL 5.7, который не поддерживает аналитические функции, вам нужно будет использовать переменные для хранения значений temp и name из предыдущей строки:

SELECT  t.ID,
        t.Name,
        t.Temp
FROM    (   SELECT  t.*,
                    IF(@temp = t.temp AND @name = t.Name, 1, 0) AS IsDuplicate,
                    @temp:= t.temp,
                    @name:= t.Name
        FROM    YourTable AS t
        CROSS JOIN (SELECT @temp := 0, @name := '') AS v
        ORDER BY t.ID
        ) AS t
WHERE   t.IsDuplicate = 0
ORDER BY ID;

Пример на БД <> Fiddle

Ключевые части (не в том порядке, в котором они появляются, а в том порядке, в котором логично думать об этом ).

(1) Инициализируйте переменные и упорядочите по идентификатору (или любым другим полям), чтобы гарантировать, что переменные назначены в правильном порядке

CROSS JOIN (SELECT @temp := 0, @name := '') AS v
ORDER BY t.ID

(2) Проверьте, соответствуют ли значения, хранящиеся в переменных, текущей строке, и отметьте 1 или 0

IIF(@temp = t.temp AND @name = t.Name, 1, 0) AS IsDuplicate

(3). Присвойте переменным значения temp и name в текущей строке, чтобы они можно проверить по следующей строке:

@temp:= t.temp,
@name:= t.Name

(4) Удалить дубликаты из окончательного набора данных:

WHERE   t.IsDuplicate = 0;

Еще до go можно изменить IsDuplicate пометьте как маркер группы и используйте GROUP BY, чтобы вы могли узнать, сколько записей было в итого, пока не отображаются дубликаты:

SELECT  MIN(ID) AS FirstID,
        t.Name,
        t.Temp,
        COUNT(*) AS Records,
        MAX(ID) AS LastID
FROM    (   SELECT  t.*,
                    @group:= IF(@temp = t.temp AND @name = t.Name, @group, @group + 1) AS GroupID,
                    @temp:= t.temp,
                    @name:= t.Name
        FROM    YourTable AS t
        CROSS JOIN (SELECT @temp := 0, @name := '', @group:= 0) AS v
        ORDER BY t.ID
        ) AS t
GROUP BY t.GroupID, t.Name, t.Temp
ORDER BY t.GroupID;

Пример на БД <> Fiddle

Это может быть избыточно для требований, но это может быть полезно, так как вы можете извлечь гораздо больше информации, чем просто идентифицируя повторяющиеся строки.

Наконец, если / когда вы обновитесь до версии 8.0 или новее, вы сможете использовать ROW_NUMBER(), или если вы переходите на любую другую СУБД, которая поддерживает ROW_NUMBER() (что в настоящее время является наиболее распространенной), затем вы можете использовать следующее:

SELECT  MIN(ID) AS FirstID,
        t.Name,
        t.Temp,
        COUNT(*) AS Records,
        MAX(ID) AS LastID
FROM    (   SELECT  t.*,
                    ROW_NUMBER() OVER(ORDER BY ID) - 
                        ROW_NUMBER() OVER(PARTITION BY Temp, Name ORDER BY ID) AS GroupID
        FROM    YourTable AS t
        ORDER BY t.ID
        ) AS t
GROUP BY t.GroupID, t.Name, t.Temp
ORDER BY t.GroupID;

Пример на БД <> Fiddle

1 голос
/ 13 января 2020

Вы хотите посмотреть на предыдущую строку, чтобы решить, показывать строку или нет. Это было бы легко с LAG, доступным с MySQL 8. С MySQL 5.7 вам нужен коррелированный подзапрос с LIMIT вместо того, чтобы получить предыдущую строку.

select *
from mytable
where not (name, temp) <=>
(
  select prev.name, prev.temp
  from mytable prev
  where prev.id < mytable.id
  order by prev.id desc
  limit 1
);

Демо: https://dbfiddle.uk/?rdbms=mysql_5.7&fiddle=4c775dbee12298cd93c5087d7085982f

1 голос
/ 13 января 2020
create table #temp (name varchar(3),temp int)
insert into #temp values ('hoi',15)
insert into #temp values ('hoi',15)
insert into #temp values ('hoi',15)
insert into #temp values ('hoi',16)
insert into #temp values ('hoi',15)
insert into #temp values ('hoi',15)
insert into #temp values ('hej',13)
insert into #temp values ('hoi',13)
insert into #temp values ('hoi',13)
insert into #temp values ('hoi',14)
insert into #temp values ('hoi',13)


;with FinalResult as (
select ROW_NUMBER()Over(partition by name,temp order by name) RowNumber,* 
from #temp
) 

select * from FinalResult where RowNumber =1
drop table #temp
1 голос
/ 13 января 2020

Если вы используете Oracle:

select name, temp from (
     select id,
            name, 
            temp, 
            lag(temp,1,-99999) over (order by id) as temp_prev
       from table 
      order by id) t
 where t.temp != t.temp_prev

может работать для вас (в зависимости от вашей Oracle версии!), Она использует аналитическую функцию LAG для просмотра значений предыдущих строк, создает временную таблицу, а затем фильтрует ее.

...