Kaip aš (ar galiu) SELECT DISTINCT keliuose stulpeliuose?

Turiu gauti visas eilutes iš lentelės, kurioje yra du stulpeliai. Todėl noriu, kad visi pardavimai neturėtų kito pardavimo, kuris įvyko tą pačią dieną už tą pačią kainą. Pardavimai, kurie yra unikalūs priklausomai nuo dienos ir kainos, bus atnaujinti iki aktyvios būsenos.

Taigi, manau:

 UPDATE sales SET status = 'ACTIVE' WHERE id IN (SELECT DISTINCT (saleprice, saledate), id, count(id) FROM sales HAVING count = 1) 

Bet mano smegenys skauda vyksta toliau.

348
10 сент. rinkiniai supjaustyti rugsėjo 10 d 2008-09-10 18:33 '08 at 18:33 2008-09-10 18:33
@ 5 atsakymai
 SELECT DISTINCT a,b,c FROM t 

maždaug lygus:

 SELECT a,b,c FROM t GROUP BY a,b,c 

Gera idėja priprasti prie „GRUPĖS BY“ sintaksės, nes ji yra galingesnė.

Jūsų prašymu norėčiau tai padaryti taip:

 UPDATE sales SET status='ACTIVE' WHERE id IN ( SELECT id FROM sales S INNER JOIN ( SELECT saleprice, saledate FROM sales GROUP BY saleprice, saledate HAVING COUNT(*) = 1 ) T ON S.saleprice=T.saleprice AND s.saledate=T.saledate ) 
387
10 сент. Joel Coehoorn atsakymas rugsėjo 10 d 2008-09-10 18:36 '08, 18:36, 2008-09-10 18:36

Jei rinksite atsakymus, juos išvalysite ir tobulinate, gausite šį puikų užklausą:

 UPDATE sales SET status = 'ACTIVE' WHERE (saleprice, saledate) IN ( SELECT saleprice, saledate FROM sales GROUP BY saleprice, saledate HAVING count(*) = 1 ); 

Kuris yra daug greičiau nei bet kuris iš jų. Tai sumažina šiuo metu priimtino atsakymo našumą 10-15 kartų (mano PostgreSQL 8.4 ir 9.1 testuose).

Bet tai vis dar toli gražu nėra optimali. Naudokite „ NOT EXISTS (anti-) pusiau NOT EXISTS dar geriau. EXISTS yra standartinis SQL, kuris egzistuoja amžinai (bent jau su „PostgreSQL 7.2“, ilgai prieš šį klausimą) ir idealiai atitinka pateiktus reikalavimus:

 UPDATE sales s SET status = 'ACTIVE' WHERE NOT EXISTS ( SELECT FROM sales s1 -- SELECT list can be empty for EXISTS WHERE s.saleprice = s1.saleprice AND s.saledate = s1.saledate AND s.id <> s1.id -- except for row itself ) AND s.status IS DISTINCT FROM 'ACTIVE'; -- avoid empty updates. see below 

„SQL Fiddle“.

Unikalus raktas, skirtas identifikuoti eilutę

Jei neturite pirminio ar unikalaus rakto raktinio žodžio (pvz., Pavyzdyje), ctid sistemos stulpelį galite pakeisti šio užklausos tikslais (bet ne kitais tikslais):

  AND s1.ctid <> s.ctid 

Kiekvienoje lentelėje turi būti pagrindinis raktas. Pridėti dar vieną, jei dar neturėjote. Siūlau serial arba IDENTITY stulpelį Postgres 10+.

Susiję su:

Kaip tai greičiau?

Pusiau prisijungusių „ EXISTS anti-gali EXISTS gali sustabdyti vertinimą, kai tik bus rastas pirmasis dublikatas (nėra prasmės žiūrėti toliau). Jei tai bazinė lentelė su nedideliu skaičiumi kopijų, tai tik šiek tiek efektyvesnė. Su daugiau dublikatų, tai tampa daug efektyvesnė.

Neįtraukite tuščių naujinimų

Jei kai kurios ar kelios eilutės jau turi status = 'ACTIVE' , jūsų naujinimas nieko nekeičia, bet vis tiek pridės naują eilutės versiją visoms išlaidoms (taikomos nedidelės išimtys). Paprastai to nenorite. Pridėkite dar vieną WHERE kaip parodyta aukščiau, kad būtų dar greičiau:

Jei status NOT NULL , galite supaprastinti:

 AND status <> 'ACTIVE'; 

Skirtingas nulinio apdorojimo skirtumas

Šis prašymas (priešingai nei šiuo metu priimtas „ Joel“ atsakymas ) NULL reikšmes laiko lygiomis. Šios dvi linijos (saleprice, saledate) bus „puikios“ (nors jos atrodo identiškos žmogaus akiai):

 (123, NULL) (123, NULL) 

Jis taip pat praeina unikalų indeksą ir beveik visur kitur, nes NULL reikšmės nėra lygios, palyginti su SQL standartu. Žr.

OTOH, GROUP BY arba DISTINCT arba DISTINCT ON() apdoroja NULL reikšmes lygiomis. Naudokite tinkamą užklausos stilių, priklausomai nuo to, ką norite pasiekti. Vis dar galite naudoti šį spartesnį užklausos stilių naudodami „ IS NOT DISTINCT FROM o ne = , jei norite, kad palyginimas būtų lygus NULL. Daugiau:

Jei visos palygintos stulpeliai yra NOT NULL , nėra jokių nesutarimų.

305
28 сент. atsakymą pateikė Erwin Brandstetter 28 sep . 2012-09-28 03:50 '12 at 3:50 2012-09-28 03:50

Problema, susijusi su jūsų užklausa, yra ta, kad naudojant GROUP BY sąlygą (kurią iš esmės naudojate atskirai) galite naudoti tik tuos stulpelius, kuriuos grupuojate arba sujungiate. Negalite naudoti stulpelio ID, nes yra galimos skirtingos vertės. Jūsų atveju visada yra tik viena reikšmė dėl HAVING sąlygos, tačiau dauguma DBVS nėra pakankamai protingos, kad ją atpažintų.

Tai turėtų veikti (ir nereikia ryšio):

 UPDATE sales SET status='ACTIVE' WHERE id IN ( SELECT MIN(id) FROM sales GROUP BY saleprice, saledate HAVING COUNT(id) = 1 ) 

Taip pat galite naudoti MAX arba AVG vietoj MIN, svarbu naudoti tik funkciją, kuri grąžina stulpelio vertę, jei yra tik viena atitikimo eilutė.

22
10 сент. Christian Berg Sep 10 atsakymas 2008-09-10 19:17 '08 at 7:17 pm 2008-09-10 19:17

Noriu pasirinkti atskiras vertes iš vienos stulpelio „GrondOfLucht“, tačiau jos turi būti rūšiuojamos pagal „rūšiavimo“ stulpelyje nurodytą tvarką. Aš negaliu gauti tik vienos stulpelio skiriamųjų vertybių naudojant

 Select distinct GrondOfLucht,sortering from CorWijzeVanAanleg order by sortering 

Tai taip pat suteiks „rūšiuoti“ stulpelį, ir kadangi „GrondOfLucht“ ir „rūšiavimas“ nėra unikalūs, rezultatas bus VISOS eilutės.

naudokite GROUP, kad pasirinktumėte „GrondOfLucht“ įrašus rūšiavimo tvarka

 SELECT GrondOfLucht FROM dbo.CorWijzeVanAanleg GROUP BY GrondOfLucht, sortering ORDER BY MIN(sortering) 
1
13 янв. Atsakymas į frans eilering Jan 13 2018-01-13 10:56 '18, 10:56 val. 2018-01-13 10:56

„Multi select“ kaip visumą galima atlikti saugiai:

 select distinct * from (select col1, col2 from table ) as x 

Kaip ji gali veikti daugelyje DBVS

0
31 янв. Abdulhafeth Sartawi atsakymas sausio 31 d 2019-01-31 11:52 '19 , 11:52 am 2019-01-31 11:52