SQL DISTINCT és TOP ugyanabban a lekérdezésben

Ezt a cikket egy kérdéssorozat ihlette, amelyet egyik olvasóm, Nan küldött nekem a közelmúltban a DISTINCT, TOP és ORDER BY kérdésekkel kapcsolatban.

A lecke összes példája a Microsoft SQL Server Management Studio és az AdventureWorks2012 adatbázis alapján készült. Ezen ingyenes eszközök használatát az Útmutató az SQL Server használatának megkezdéséhez című könyvem segítségével kezdheti el.

Hogyan működnek együtt az SQL Top és a Distinct SELECT módosítók az eredmények előállításához?

Itt a kérdés, amelyet Nan eredetileg küldött nekem:

Egy kicsit össze vagyok zavarodva a SELECT DISTINCT és a SELECT kapcsán. Például,

SELECT DISTINCT TOP 10 FirstName,
LastName
FROM Person.Person
ORDER BY LastName

Ez különálló keresztneveket keres? Különálló kombinált kereszt- és vezetékneveket? Hogyan különböztetjük meg a megkülönböztetett kiértékeléshez használt oszlopokat és azokat az oszlopokat, amelyeket csak meg akarunk jeleníteni a kimeneten?

Mi a helyzet a

Select Distinct TOP 10 LastName,
FirstName + ' ' + LastName AS FullName
FROM Person.Person
ORDER BY LastName

Gondoltam, mindenki szeretné tudni a választ, ezért létrehozok egy blogbejegyzést.

DISTINCT és TOP – Melyik az első?

Nézzük meg az első utasítást, amelynek célja, hogy az ö- és vezetéknevek egyedi listáját adja vissza.

SELECT DISTINCT TOP 10 FirstName,
LastName
FROM Person.Person
ORDER BY LastName;

A TOP 10 az első tíz elemet adja vissza a rendezett halmazból, a DISTINCT pedig eltávolítja a duplikátumokat. A kérdés az, hogy mi történik először?

  • A táblázatot Utónév szerint rendezi, és az első tíz elemet veszi ki, majd eltávolítja a duplikált neveket?
  • Vagy eltávolítja a duplikátumokat, majd rendezi az elemeket, és megjeleníti az első tíz elemet?

Mielőtt válaszolnánk erre a kérdésre, tartsuk szem előtt, hogy a DISTINCT a SELECT záradékban szereplő összes oszlopra és kifejezésre hat. Tehát ebben az esetben az utasítás külön sorokat fog visszaadni a FirstName és a LastName számára.

Sajnos nincs közvetlen módja annak, hogy a DISTINCT-et a mezők egy csoportjára használjuk, a többit pedig megjelenítsük. Amint oszlopokat adunk hozzá a SELECT utasításhoz, azok a DISTINCT operátor hatása alá kerülnek. Direktet mondok, mivel kaphatsz egy distinct listát, majd egy INNER JOIN segítségével behúzhatod a többi oszlopot. Ennek azonban vannak veszélyei, mivel az összekapcsolás ismét duplikátumokat hozhat létre.

Érdekes a TOP záradék hozzáadása a DISTINCT-hez. Nem voltam biztos benne, hogy mi fog történni, de kísérleteztem egy kicsit az AdventureWorks adatbázisával, és azt találtam, hogy a feldolgozás sorrendje valahogy így néz ki:

  1. DISTINCT értékek kiválasztása a táblázatból és rendezése
  2. Az 1. lépés eredményei közül a TOP x sor kiválasztása és megjelenítése.

Ha ki akarja próbálni ezt maga, kezdje

SELECT FirstName,
LastName
FROM Person.Person
ORDER BY LastName

És figyelje az eredményeket. Tartsd szemmel a “Kim Ambercombie”-t. Figyeld meg, hogy három bejegyzés van a nevére.

Eredmények vezetéknév szerint rendezve

Most futtasd le

SELECT DISTINCT FirstName,
LastName
FROM Person.Person
ORDER BY LastName

És látni fogod, hogy “Kim Ambercombie” csak egyszer jelenik meg.

Egyedi lista Utónév szerint rendezve

Majd futtassa

SELECT DISTINCT TOP 10 FirstName,
LastName
FROM Person.Person
ORDER BY LastName

És látni fogja, hogy az első 10 egyedi elő- és utónevet adja vissza Utónév szerint rendezve.

Az első 10 egyedi sor Utónév szerint rendezve

Ha kíváncsi, hogy melyik történik előbb, a DISTINCT vagy a TOP 10 művelet, akkor hasonlítsa össze az utolsó két lekérdezés eredményeit.

Figyeljen arra, hogy a “DISTINCT TOP 10” lekérdezés a “DISTINCT” lekérdezésből az első 10 sort tartalmazza.

Ebből tudjuk, hogy először egy DISTINCT lista jön létre, majd a TOP 10 elemet adja vissza.

A lekérdezési terv mutatja a végrehajtás sorrendjét

A lekérdezési terv megjelenítésével is megerősíthetjük ezt. Ehhez a lekérdezés végrehajtása előtt válassza a menüből a Query -> Include Actual Query Plan parancsot.

A “Stream Aggregate” ikon a DISTINCT műveletet, a “Top” pedig a TOP 10 műveletet jelöli.

Egy kicsit ellentmondásosnak tűnhet, hogy a SELECT utasításon belül a DISTINCT szerepel először. Ne feledje, hogy az SQL nem feltétlenül abban a sorrendben kerül feldolgozásra, ahogyan az ember balról jobbra olvasná.

DISTINCT és TOP a SELECT lista kifejezéseivel

Nan kérdésének második része arra vonatkozott, hogy a kifejezéseket hogyan kezeli a DISTINCT operátor.

A kifejezéseket a DISTINCT és a TOP tekintetében ugyanúgy kezeli, mint az oszlopot. Kezdjük egy select utasítással, hogy megkapjuk a keresztnevet, valamint a teljeset, amelyet úgy hozunk létre, hogy a LastName-et a FirstName-hez csatoljuk.

Az ORDER BY használatakor is tartsuk szem előtt, hogy a Distinct használatakor az ORDER BY elemeknek meg kell jelenniük a select listában. Ezt figyelembe véve módosítanom kell az eredeti kérdésben bemutatott utasítást:

SELECT DISTINCT FirstName,
FirstName + ' ' + LastName AS FullName
FROM Person.Person
ORDER BY LastName

Nem fog futni, mivel a LastName nem szerepel a SELECT listában. Igen, része egy kifejezésnek a select listában, de önmagában nincs ott. Érvényes a FullName szerinti rendezés.

Az alábbi példákban ezt a rendezést fogjuk használni.

Az utasítás

SELECT FirstName,
FirstName + ' ' + LastName AS FullName
FROM Person.Person
ORDER BY FirstName + ' ' + LastName

Megkapja az 19972 sort. Ha hozzáadjuk a Distinct

SELECT DISTINCT FirstName,
FirstName + ' ' + LastName AS FullName
FROM Person.Person
ORDER BY FirstName + ' ' + LastName

Aztán 19516 sort kapunk vissza. Végül a Top 10 hozzáadása az első 10 különböző névkombinációt adja vissza.

SELECT DISTINCT TOP 10 FirstName,
FirstName + ' ' + LastName AS FullName
FROM Person.Person
ORDER BY FirstName + ' ' + LastName

Próbálja meg futtatni ezeket a lekérdezéseket az AdventureWork adatbázisban, és meggyőződhet róla, hogy a viselkedés ugyanaz, mint amikor kizárólag oszlopokkal dolgozunk.

Kizárólag oszlopokkal dolgozunk.

Vélemény, hozzászólás?

Az e-mail-címet nem tesszük közzé.