ВИДАЛЕНО лише для одного стовпця


155

Скажімо, у мене є наступний запит.

SELECT ID, Email, ProductName, ProductModel FROM Products

Як я можу змінити його, щоб він не повертав повторюваних електронних листів?

Іншими словами, коли кілька рядків містять один і той же електронний лист, я хочу, щоб результати включали лише один із цих рядків (бажано останній). Дублікати в інших стовпцях повинні бути дозволені.

Клаузи подобаються DISTINCTі, GROUP BYздається, працюють на цілі рядки. Тож я не впевнений, як до цього підійти.


2
Гаразд, вам потрібно використовувати PARTITION або використовувати два оператори вибору?
CarneyCode

І що потрібно показати, якщо є 2 рядки з однаковою адресою електронної пошти, але різними продуктами? ( Переважно останній) не зрозуміло. Останнє, яким замовленням?
ypercubeᵀᴹ

@ypercube Як зазначено у запитанні, бажано останньому. Однак це не дуже важливо для мене. Я просто хочу одного з них.
Джонатан Вуд

1
Ви можете подивитися на наступні питання: питання1 , питання2 або питання3 .
Маріан

Чому ви не можете використовувати: ВИБІР ВИДАЛЕНОЇ електронної пошти, ідентифікатора, імені продукту, продукту від моделей?
Рік Хендерсон

Відповіді:


186

Якщо ви використовуєте SQL Server 2005 або вище, використовуйте це:

SELECT *
  FROM (
                SELECT  ID, 
                        Email, 
                        ProductName, 
                        ProductModel,
                        ROW_NUMBER() OVER(PARTITION BY Email ORDER BY ID DESC) rn
                    FROM Products
              ) a
WHERE rn = 1

EDIT: Приклад використання пункту де:

SELECT *
  FROM (
                SELECT  ID, 
                        Email, 
                        ProductName, 
                        ProductModel,
                        ROW_NUMBER() OVER(PARTITION BY Email ORDER BY ID DESC) rn
                    FROM Products
                   WHERE ProductModel = 2
                     AND ProductName LIKE 'CYBER%'

              ) a
WHERE rn = 1

4
Я повинен розслідувати цю частину ПАРТІЙ, ніколи не бачив її в дії. Дякую за приклад
LorenVS

@Cybernate Одне ускладнення: мій внутрішній SELECTпотребує WHEREстану. Я думаю, номери рядків будуть призначені для всіх рядків таблиці. Цей синтаксис трохи більше за мене. Будь-який шанс оновлення, який би гарантував один рядок із певною електронною поштою, яка відповідає WHEREумові?
Джонатан Вуд

1
Ви можете додати пункт до внутрішнього sql. Я оновлю публікацію, коли зможу отримати доступ до свого ноутбука
Чанду

1
Оновлено публікацію зразком, використовуючи пункт де.
Чанду

1
Я правильно працюю лише тоді, коли в запиті немає JOIN s. Як тільки у мене є JOIN, ROW_NUMBERповертається набагато вище значень, ніж "1".
Уве Кеїм

10

Це передбачає, що SQL Server 2005+ і ваше визначення "останнього" - це максимум ПК для даної електронної пошти

WITH CTE AS
(
SELECT ID, 
       Email, 
       ProductName, 
       ProductModel, 
       ROW_NUMBER() OVER (PARTITION BY Email ORDER BY ID DESC) AS RowNumber 
FROM   Products
)
SELECT ID, 
       Email, 
       ProductName, 
       ProductModel
FROM CTE 
WHERE RowNumber = 1

6

Коли ви використовуєте, DISTINCTдумайте про це як окремий рядок, а не стовпець. Він поверне лише рядки, де стовпці не збігаються абсолютно однаково.

SELECT DISTINCT ID, Email, ProductName, ProductModel
FROM Products

----------------------
1 | something@something.com | ProductName1 | ProductModel1
2 | something@something.com | ProductName1 | ProductModel1

Запит поверне обидва рядки, оскільки IDстовпець інший. Я припускаю, що IDстовпець - це IDENTITYстовпчик, який збільшується, якщо ви хочете повернути останній, то я рекомендую щось подібне:

SELECT DISTINCT TOP 1 ID, Email, ProductName, ProductModel
FROM Products
ORDER BY ID DESC

Повідомлення TOP 1поверне лише перший запис, впорядкувавши його за IDспаданням, він поверне перші результати останнім рядком. Це дасть вам останній запис.


2
Як зазначено в запитанні, я бачу, що DISTINCT працює на весь ряд. Я хочу зробити так, як ви пропонуєте вище, але кожен раз, коли електронний лист дублюється в результатах (не один раз).
Джонатан Вуд

У такому випадку я рекомендую перейти з відповіддю @Cybernate. Це має робити саме те, що вам потрібно.
jon3laze

4

Ви можете це зробити за допомогою функції GROUP BY

SELECT ID, Email, ProductName, ProductModel FROM Products GROUP BY Email


16
Стовпець "Products.ID" недійсний у списку вибору, оскільки він не міститься ні в сукупній функції, ні в пункті GROUP BY.
palota

2
Це не працює, не використовуючи щось на зразок MAX (ID), MAX (ProductName), MAX (ProductModel) для інших стовпців
avl_sweden

2
У постграфах вам потрібна лише функція сукупності на стовпці, яка буде використовуватися в групі за допомогою пункту, наприклад SELECT id, max(email) AS email FROM tbl GROUP by email. На сервері SQL ВСІ стовпці в SELECTпункті повинні бути у сукупній функції. Це мене кусає щоразу, коли я повертаюся назад.
Брюс Пірсон

Це ніколи не вийде. Це погане рішення
Dan AS

1

Для доступу ви можете скористатися запитом SQL Select, який я представляю тут:

Наприклад, у вас є ця таблиця:

КЛІЄНТ || НОМБРЕС || ПОЧТА

888 || T800 ARNOLD || t800.arnold@cyberdyne.com

123 || JOHN CONNOR || s.connor@skynet.com

125 || SARAH CONNOR ||s.connor@skynet.com

І потрібно вибирати лише окремі листи. Ви можете зробити це за допомогою цього:

SQL SELECT:

SELECT MAX(p.CLIENTE) AS ID_CLIENTE
, (SELECT TOP 1 x.NOMBRES 
    FROM Rep_Pre_Ene_MUESTRA AS x 
    WHERE x.MAIL=p.MAIL 
     AND x.CLIENTE=(SELECT MAX(l.CLIENTE) FROM Rep_Pre_Ene_MUESTRA AS l WHERE x.MAIL=l.MAIL)) AS NOMBRE, 
p.MAIL
FROM Rep_Pre_Ene_MUESTRA AS p
GROUP BY p.MAIL;

Ви можете використовувати це для вибору максимального ідентифікатора, імені кореспондента до цього максимального ідентифікатора. Ви можете додати будь-який інший атрибут таким чином. Потім в кінці ви ставите окремий стовпчик для фільтрування, і ви лише групуєте його з останнім окремим стовпцем.

Це дасть вам максимальний ідентифікатор з відповідними даними, ви можете використовувати min або будь-які інші функції, і ви повторите цю функцію в підзапити.

Цей вибір поверне:

КЛІЄНТ || НОМБРЕС || ПОЧТА

888 || T800 ARNOLD || t800.arnold@cyberdyne.com

125 || SARAH CONNOR ||s.connor@skynet.com

Не забудьте проіндексувати вибрані стовпці, і окремий стовпець не повинен містити числових даних у верхньому та нижньому регістрі, інакше він не працюватиме. Це також буде працювати лише з однією зареєстрованою поштою. Щасливого кодування !!!


0

Причина DISTINCTі GROUP BYробота над цілими рядками полягає в тому, що ваш запит повертає цілі рядки.

Щоб зрозуміти: Спробуйте записати вручну, що запит повинен повернутись, і ви побачите, що неоднозначно, що потрібно поставити у не дублюються стовпці.

Якщо вам буквально все одно, що знаходиться в інших стовпцях, не повертайте їх. Повернення випадкового рядка для кожної адреси електронної пошти мені здається трохи марним.


@JohnFix Я хочу повернути цілі рядки. Я просто не хочу, щоб рядки поверталися, коли результати вже містять рядок з тим самим значенням у стовпці Електронна пошта.
Джонатан Вуд

Тож як слід вирішити, кого повернути? Ви дійсно хочете запит, який повертає довільний рядок для кожної електронної пошти. Це справді пахне, як вам може знадобитися переосмислити проблему, яку ви намагаєтеся вирішити. Майже щоразу, коли мені задають це питання (і його виникає багато), виявляється, розробник не продумав наслідки такої поведінки в додатку.
JohnFx

6
У мене справді виникають проблеми з дотриманням вашої логіки. Як зазначено у запитанні, я віддаю перевагу останньому (відсортованому за ідентифікацією). Так, якби він обрав випадковий рядок, це було б добре. І так, я подумав про це.
Джонатан Вуд

0

Спробуйте це

;With Tab AS (SELECT DISTINCT Email FROM  Products)
SELECT Email,ROW_NUMBER() OVER(ORDER BY Email ASC) AS  Id FROM Tab
ORDER BY Email ASC

-2

Спробуйте це:

SELECT ID, Email, ProductName, ProductModel FROM Products WHERE ID IN (SELECT MAX(ID) FROM Products GROUP BY Email)

2
Навіщо нам це намагатися? Чому це краще, ніж інші відповіді, розміщені тут за останні 8 років? Якщо ви хочете поділитися кращим способом вирішення проблеми, вам потрібно пояснити, чому ви її рекомендуєте.
Дхарман
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.