Det här är ett avsnitt i en
webbkurs om databaser
som finns fritt tillgänglig på adressen
http://www.databasteknik.se/webbkursen/.
Senaste ändring:
18 juli 2005.
Av Thomas Padron-McCarthy. Copyright, alla rättigheter reserverade, osv. Skicka gärna kommentarer till webbkursen@databasteknik.se.
|
Det kan vara bra att läsa avsnittet om relationsmodellen först.
select * from Medlem;Kommandot, eller SQL-frågan, "select * from Medlem" betyder ungefär "välj ut alla kolumnerna ur tabellen Medlem". Semikolonet på slutet ingår egentligen inte i SQL-frågan, men behövs ibland för att markera slutet på frågan, eller för att skilja olika SQL-frågor åt.
När du kör denna SQL-fråga kommer du som svar att få en tabell som liknar den här:
Medlemsnummer Namn Telefon 2 Stina 282677 3 Saddam 260088 4 Lotta 174590 1 Olle 260088
Exakt hur du gör för att "köra frågan" beror på vilken databashanterare du använder. På vissa system kanske du har ett särskilt fönster där du kan skriva in och redigera frågan, varefter du kör den genom att klicka med musen på en knapp som det står Kör på. I andra system skriver du in frågan, avslutar den med ett semikolon (;), och sen när du trycker på returtangenten så körs frågan.
Det här är innehållet i tabellen Medlem i databasen. Den tabellen innehåller data om klubbens medlemmar. Varje rad beskriver en medlem. Som vi ser har tabellen tre kolumner, nämligen Medlemsnummer (medlemsnummer), Namn (medlemmens namn) och Telefon (medlemmens telefonnummer).
Faktaruta: Ibland kallar man tabellerna för relationer, raderna för tupler, och kolumnerna för attribut. |
Varje rad (eller tupel) beskriver en sak av något slag, i det här fallet en medlem i idrottsklubben, och varje kolumn (eller attribut) beskriver en egenskap hos en sådan sak, exempelvis dess nummer eller namn.
Alla värden i samma kolumn (för samma attribut) har samma typ, och mängden av alla värden som kan finnas i kolumnen brukar vi kalla domän. Det motsvarar ungefär begreppet datatyp i programmeringsspråk.
select Namn from Medlem;Med kommandot "select Namn from Medlem" menar vi helt enkelt "välj ut kolumnen Namn ur raderna i tabellen Medlem".
Namn Stina Saddam Lotta Olle
Vi kan välja ut mer än en kolumn om vi vill, till exempel namnet och telefonnumret (attributen Namn och Telefon):
select Namn, Telefon from Medlem;
Namn Telefon Stina 282677 Saddam 260088 Lotta 174590 Olle 260088
Faktaruta: Om du kan någon relationsalgebra, så motsvarar det här operationen projektion ("project" på engelska) i relationsalgebran: en operation som väljer ut vissa av kolumnerna i en relation (dvs tabell). |
Den första frågan vi ställde, select * from Medlem, skulle också kunna uttryckas så här:
select Medlemsnummer, Namn, Telefon from Medlem;Vi har nu sett hur man kan använda select för att välja ut de av tabellens kolumner (relationens attribut) som man är intresserad av. Men vi kan också tala om vilka rader (tupler) vi vill ha med i svaret. Om vi vill ha information bara för den medlem som heter Lotta, skriver vi:
select * from MedlemMed ordet where kunde vi alltså ange ett "sökvillkor", som talade om vilka tupler vi var intresserade av.
where Namn = 'Lotta';
Medlemsnummer Namn Telefon 4 Lotta 174590
Faktaruta: Om du kan någon relationsalgebra, så motsvarar det här operationen selektion ("select" på engelska) i relationsalgebran: en operation som väljer ut de rader i en relation (dvs tabell) som uppfyller ett visst villkor. Relationsalgebrans select har inget att göra med den select som vi har i SQL, som bara betyder ungefär att "här börjar en SQL-fråga". |
Notera att i SQL använder vi enkla citationstecken (') för att avgränsa strängar, inte dubbla ("). Det brukar funka med dubbla citationstecken också, men egentligen ska det vara enkla.
Vi skulle kunna omformulera frågan så här:
select * from MedlemSvaret blir:
where Medlem.Namn = 'Lotta';
Medlem.Namn betyder här "kolumnen Namn i tabellen Medlem", men eftersom det än så länge inte kan uppstå några missförstånd, räcker det med att skriva Namn, utan någon tabellangivelse.
Medlemsnummer Namn Telefon 4 Lotta 174590
Vi kan också göra strängmatchning med jokertecken (eller wildcards som det heter på engelska):
select Namn, Telefon from MedlemOm man använder ordet "like" i jämförelsen, så innebär det strängmatchning med jokertecken. Understreck (_) betyder ett tecken, vilket som helst, medan procenttecken (%) betyder vilka tecken som helst, "=" funkar som exakt match:
where Namn like 'S%';
Namn Telefon Stina 282677 Saddam 260088
select Namn, Telefon from MedlemMan kan bygga upp mer komplicerade where-villkor med hjälp av AND och OR, på samma sätt som man brukar kunna göra i programmeringsspråk:
where Namn = 'S%';
Namn Telefon
select * from MedlemUttrycken kan grupperas med parenteser:
where Namn like 'S%' and Medlemsnummer <= 2
or Telefon = '174590';
Medlemsnummer Namn Telefon 2 Stina 282677 4 Lotta 174590
select * from Medlem
where Namn like 'S%' and (Medlemsnummer <= 2
or Telefon = '174590');
Medlemsnummer Namn Telefon 2 Stina 282677
select * from Medlem
where Förnamn = 'Lotta';[interbase.interclient] Dynamic SQL Error SQL error code = -206 Column unknown FÖRNAMN
select * from Medlemm
where Namn = 'Lotta';[interbase.interclient] Dynamic SQL Error SQL error code = -204 Table unknown MEDLEMM
select * from Sektion;Varje rad i tabellen Sektion innehåller data om en av klubbens sektioner. Tabellen har tre kolumner, nämligen Sektionskod (sektionskod), Namn (sektionens namn) och Ledare (ledare).
Sektionskod Namn Ledare A Bowling 4 C Simning 2 B Kickboxing 4
Ledare anger medlemsnumret på den medlem som är ledare för sektionen. Vi ser till exempel att medlem nummer 4 leder bowlingsektionen, och vi kan sen gå till medlemstabellen för att ta reda på vem medlem nummer 4 är. Medlemstabellen såg ju ut så här:
Vi ser alltså att det är Lotta som leder bowlingsektionen.
Medlemsnummer Namn Telefon 2 Stina 282677 3 Saddam 260088 4 Lotta 174590 1 Olle 260088
Faktaruta: Ett attribut (dvs en kolumn) som på det viset refererar till en annan tabell kallas referensattribut. Den kan också kallas främmande nyckel (foreign key på engelska) eftersom den refererar till en nyckel i en annan tabell. |
Tabellerna i exemplet är så små att vi direkt ser att ledaren för bowlingsektionen är Lotta. Men om det är stora tabeller vill man förstås använda SQL-frågor för att få fram den informationen. Vi ska nu försöka oss på att göra detta.
Vi börjar med det mest uppenbara (men inte särskilt bra) sättet.
Först tar vi fram numret på bowlingsektionens ledare:
select Ledare from SektionOch sen tittar vi helt enkelt efter i medlemstabellen vem nummer 4 är:
where Namn = 'Bowling';
Ledare 4
select Namn from MedlemDet är dock ganska onödigt att ställa två separata frågor. I andra fall kan det dessutom bli väldigt krångligt.
where Medlemsnummer = 4;
Namn Lotta
I den andra frågan, select Namn from Medlem where Medlemsnummer = 4, var ju 4:an resultatet av den första frågan, select Ledare from Sektion where Namn = 'Bowling'. Därför stoppar vi in denna första fråga i den andra frågan, i stället för 4:an!
select Namn from MedlemNotera att vi behövde skriva parenteser runt den andra, inre frågan.
where Medlemsnummer = (select Ledare from Sektion
where Namn = 'Bowling');
Namn Lotta
Prova först att skriva båda tabellerna Sektion och Medlem efter from i select-frågan:
select * from Sektion, Medlem;Resultatet blir den så kallade kartesiska produkten av de två tabellerna, dvs alla kombinationer av rader. Låt oss nu välja ut bara de rader där ledarnumret Ledare är samma som medlemsnumret Medlemsnummer:
Sektionskod Namn Ledare Medlemsnummer Namn Telefon A Bowling 4 2 Stina 282677 C Simning 2 2 Stina 282677 B Kickboxing 4 2 Stina 282677 A Bowling 4 3 Saddam 260088 C Simning 2 3 Saddam 260088 B Kickboxing 4 3 Saddam 260088 A Bowling 4 4 Lotta 174590 C Simning 2 4 Lotta 174590 B Kickboxing 4 4 Lotta 174590 A Bowling 4 1 Olle 260088 C Simning 2 1 Olle 260088 B Kickboxing 4 1 Olle 260088
select * from Sektion, MedlemVi har plötsligt fått en fin liten tabell där varje rad innehåller information om en sektion och dess ledare.
where Ledare = Medlemsnummer;
Sektionskod Namn Ledare Medlemsnummer Namn Telefon C Simning 2 2 Stina 282677 A Bowling 4 4 Lotta 174590 B Kickboxing 4 4 Lotta 174590
Vi var ju egentligen bara intresserade av bowlingsektionens ledare, så vi lägger in det också i where-villkoret:
select * from Sektion, MedlemOch så gör vi en sista ändring, för att få fram bara namnet på ledaren:
where Ledare = Medlemsnummer
and Sektion.Namn = 'Bowling';
Sektionskod Namn Ledare Medlemsnummer Namn Telefon A Bowling 4 4 Lotta 174590
select Medlem.Namn from Sektion, Medlem
where Ledare = Medlemsnummer
and Sektion.Namn = 'Bowling';
Namn Lotta
select * from Deltar;Av den första raden i tabellen ser vi att medlem nummer 1 deltar i sektionen med sektionskoden A. På nästa rad står det att (samma) medlem nummer 1 också deltar i sektionen med sektionskoden B. Och så vidare.
Medlem Sektion 1 A 1 B 1 C 2 C 3 A
Nu vill vi använda alla tre tabellerna i databasen (Medlem, Sektion och Deltar) för att svara på frågan Vilka sporter ägnar sig Olle åt?
Först gör vi på det dumma sättet, och börjar med att ta reda på Olles medlemsnummer:
select MedlemsnummerSen tittar vi i tabellen Deltar för att få reda på vilka av sektionerna som Olle deltar i.
from Medlem
where Namn = 'Olle';
Medlemsnummer 1
select Sektion from DeltarOk, så vad är 'A', 'B' och 'C' för nåt?
where Medlem = 1;
Sektion A B C
select Namn from SektionVi kan skriva det lite enklare med "in":
where Sektionskod = 'A'
or Sektionskod = 'B'
or Sektionskod = 'C';
Namn Bowling Simning Kickboxing
select Namn from SektionDet var alltså det dumma sättet. Nu ska vi i stället skriva ihop de tre frågorna till en enda fråga.
where Sektionskod in ('A', 'B', 'C');
Namn Bowling Simning Kickboxing
Först stoppar vi in en sub-select för att slippa det hårdkodade ('A', 'B', 'C'):
select Namn from SektionOops! Vi måste använda "in" i stället för "=". Den vanliga lika-med-jämförelsen med "=" kan nämligen bara jämföra med ett värde, och här är det ju tre (eftersom Olle deltar i tre sektioner).
where Sektionskod = (select Sektion from Deltar
where Medlem = 1);[interbase.interclient] multiple rows in singleton select
select Namn from SektionOch så stoppar vi in den första frågan, select Medlemsnummer from Medlem where Namn = 'Olle', i stället för 1:an.
where Sektionskod in (select Sektion from Deltar
where Medlem = 1);
Namn Bowling Simning Kickboxing
select Namn from SektionGör samma fråga men utan nån jämrans sub-select:
where Sektionskod in (select Sektion from Deltar
where Medlem = (select Medlemsnummer from Medlem
where Namn = 'Olle'));
Namn Bowling Simning Kickboxing
select Namn from Sektion, Deltar, MedlemÖh, vanurå? Jo, den dumma databashanterare vi använde i exemplet borde nog ha varnat oss för att det finns två kolumner som heter "Namn" i de tabeller som frågan handlar om, nämligen Namn i Sektion.Namn och Medlem.Namn. I stället valde den en av dem, och det råkade bli Medlem.Namn!
where Sektionskod = Sektion
and Medlem = Medlemsnummer
and Namn = 'Olle';
Namn Olle Olle Olle
Vi skriver om frågan så det blir rätt:
select Sektion.Namn
from Sektion, Deltar, Medlem
where Sektionskod = Sektion
and Medlem = Medlemsnummer
and Medlem.Namn = 'Olle';
Namn Bowling Kickboxing Simning
select * from MedlemFrågan kan också, som vi sett ovan, skrivas om utan någon select-sats i where-villkoret:
where Medlemsnummer in (select Medlem from Deltar);
Medlemsnummer Namn Telefon 2 Stina 282677 3 Saddam 260088 1 Olle 260088
select distinct Medlem.Medlemsnummer, Medlem.Namn, Medlem.TelefonDistinct behövs eftersom medlemmar som deltar i flera sektioner annars kommer med flera gånger i svaret. I den teoretiska relationsmodellen finns inga dubletter, men SQL behåller dem för det mesta. Orsaken är dels att det går fortare att ta fram svaret om databashanteraren slipper sortera bort dubletter, men också att användaren ofta är intresserad av dubletterna också.
from Medlem, Deltar
where Medlem.Medlemsnummer = Deltar.Medlem;
Om vi vill veta vilka som inte deltar i någon sektion, stoppar vi bara in ett not:
select * from MedlemEn fråga som innehåller "... in (select ..." i where-villkoret kunde ju skrivas om med en vanlig likhet. Men "... not in (select ..." kan inte lika enkelt skrivas om. Frågan ovan kan man alltså inte skriva om så här:
where Medlemsnummer not in (select Medlem from Deltar);
Medlemsnummer Namn Telefon 4 Lotta 174590
select distinct Medlem.Medlemsnummer, Medlem.Namn, Medlem.TelefonDen frågan tar inte fram vilka som inte sportar, utan den tar fram alla medlemmar som inte är helt ensamma om att sporta! (Tänk så här: Varje medlem som går att para ihop med en rad i deltar-tabellen som inte handlar om henne själv.)
from Medlem, Deltar
where Medlem.Medlemsnummer != Deltar.Medlem;
Här kommer några enkla aggregatfunktioner. Vad är det högsta medlemsnumret?
select max(Medlemsnummer) from Medlem;Och vem är det som har det högsta medlemsnumret?
MAX 4
select * from MedlemNej, man kan inte ha aggregatfunktioner i where-villkoret. Gör en sub-fråga:
where Medlemsnummer = max(Medlemsnummer);[interbase.interclient] Dynamic SQL Error SQL error code = -104 Invalid aggregate reference
select * from MedlemMan kan också kombinera aggregatfunktioner med ett where-villkor, vilket gör att aggregatfunkionen bara beräknas för de rader som uppfyller where-villkoret. För att få fram det högsta medlemsnumret för medlemmar med namn som börjar på S:
where Medlemsnummer = (select max(Medlemsnummer) from Medlem);
Medlemsnummer Namn Telefon 4 Lotta 174590
select max(Medlemsnummer) from Medlem
where Namn like 'S%';
MAX 3
Nu ska vi testa vyer. Visa sektionsnamn och namnet på ledaren för den sektionen:
select Sektion.Namn, Medlem.NamnVi gör en vy av det:
from Sektion, Medlem
where Ledare = Medlemsnummer;
Namn Namn Simning Stina Bowling Lotta Kickboxing Lotta
create view LedarskapÖh, gick ju inte. I svaret på en fråga, som bara ska skrivas ut, kan man tillåta två kolumner med samma namn, men inte i en vy eller tabell. Det fungerar bättre om vi ger namn till kolumnerna i vyn, till exempel så här:
as select Sektion.Namn, Medlem.Namn
from Sektion, Medlem
where Ledare = Medlemsnummer;[interbase.interclient] unsuccessful metadata update STORE RDB$RELATION_FIELDS failed attempt to store duplicate value (visible to active transactions) in unique index "RDB$INDEX_15"
create view Ledarskap (Sektionsnamn, Medlemsnamn)Nu funkar vyn som vilken tabell som helst.
as select Sektion.Namn, Medlem.Namn
from Sektion, Medlem
where Ledare = Medlemsnummer;Ok
select * from Ledarskap;
Sektionsnamn Medlemsnamn Simning Stina Bowling Lotta Kickboxing Lotta
select Medlemsnamn
from Ledarskap
where Sektionsnamn = 'Bowling';
Medlemsnamn Lotta
select * from Medlem;
Medlemsnummer Namn Telefon 2 Stina 282677 3 Saddam 260088 4 Lotta 174590 1 Olle 260088
insert into MedlemAha! Databasen kollar att vi inte har dubletter på primärnyckeln: Så här skrev vi när vi skapade tabellen:
values (4, 'Isaac', 281000);[interbase.interclient] violation of PRIMARY or UNIQUE KEY constraint "INTEG_16" on table "Medlem"
create table MedlemGör rätt, dvs använd ett nummer som är unikt:
(Medlemsnummer integer not null,
Namn varchar(6),
Telefon varchar(10),
primary key (Medlemsnummer));
insert into Medlem
values (7, 'Isaac', 281000);Ok (1 row affected)
select * from Medlem;Om det fattas ett värde, till exempel om vi vill lägga in medlemmen Nelson som inte har någon telefon?
Medlemsnummer Namn Telefon 2 Stina 282677 3 Saddam 260088 4 Lotta 174590 1 Olle 260088 7 Isaac 281000
insert into Medlem values (8, 'Nelson');I det läget måste man lista namnen på kolumnerna![interbase.interclient] Dynamic SQL Error SQL error code = -804 Count of columns does not equal count of values
insert into Medlem (Medlemsnummer, Namn)
values (8, 'Nelson');Ok (1 row affected)
select * from Medlem;Nelsons telefon fick värdet null. Nelson har alltså inte något telefonnummer lagrat i tabellen, utan rutan är tom. (Det kan betyda att Nelson inte har någon telefon, eller också att vi bara inte vet numret.)
Medlemsnummer Namn Telefon 2 Stina 282677 3 Saddam 260088 4 Lotta 174590 1 Olle 260088 7 Isaac 281000 8 Nelson
select * from Medlem where Telefon is null;Notera att man måste använda "is null". Null är inte samma sak som noll eller en tom sträng:
Medlemsnummer Namn Telefon 8 Nelson
select * from Medlem where Telefon = '';Nu känner vi plötsligt för att ge kommandot commit:
Medlemsnummer Namn Telefon
commit;I och med att vi gjort commit, är ändringarna "sparade" i databasen. De kommer inte att försvinna om datorn kraschar eller om strömmen går, och i ett fleranvändarsystem blir de nu synliga för andra användare.Transaction committed
Kan vi ta bort rader också? Testa att ta bort en medlem:
delete from Medlem where Namn = 'Isaac';Ok (1 row affected)
select * from Medlem;Nu testar vi att ge kommandot rollback. Vid en rollback försvinner alla ändringar sen senaste commit, eller sen sessionens början om vi aldrig "commitat". Och plötsligt finns Isaac där igen:
Medlemsnummer Namn Telefon 2 Stina 282677 3 Saddam 260088 4 Lotta 174590 1 Olle 260088 8 Nelson
rollback;Transaction aborted
select * from Medlem;Du kan läsa mer om commit och rollback i avsnittet om transaktioner.
Medlemsnummer Namn Telefon 2 Stina 282677 3 Saddam 260088 4 Lotta 174590 1 Olle 260088 7 Isaac 281000 8 Nelson
Testa nu att ta bort Lotta:
delete from Medlem where Namn = 'Lotta';Gick inte. Lotta refereras ju till (som ledare) från Sektion-tabellen. Databashanteraren upprätthåller referensintegritet för kopplingar mellan tabellerna med referensattribut. Referensintegritet betyder att om det nu står på en rad i sektionstabellen att medlem nummer 4 leder sektionen, så ska det banne mig också finnas en medlem nummer 4 i medlemstabellen.[interbase.interclient] violation of FOREIGN KEY constraint "INTEG_36" on table "Sektion"
En gång har vi skrivit så här för att tala om för databashanteraren att Ledare i Sektion är ett referensattribut:
alter table Sektion add foreign key (Ledare) references Medlem (Medlemsnummer);
Du kan läsa mer om referensintegritet och andra liknande kontroller i avsnittet om integritetsvillkor.
Till sist ska vi också se att vi kan ändra rader med kommandot update:
update Sektion
set Namn = 'Skydiving'
where Namn = 'Bowling';
Ok (1 row affected)select * from Sektion;
Sektionskod Namn Ledare A Skydiving 4 C Simning 2 B Kickboxing 4
create table Medlem (Medlemsnummer integer not null, Namn varchar(6), Telefon varchar(10), primary key (Medlemsnummer)); create table Sektion (Sektionskod character(1) not null, Namn varchar(10), Ledare integer, primary key (Sektionskod)); create table Deltar (Medlem integer not null, Sektion character(1) not null, primary key (Medlem, Sektion)); alter table Sektion add foreign key (Ledare) references Medlem (Medlemsnummer); alter table Deltar add foreign key (Medlem) references Medlem (Medlemsnummer); alter table Deltar add foreign key (Sektion) references Sektion (Sektionskod);
insert into Medlem (Medlemsnummer, Namn, Telefon) values (2, 'Stina', '282677'); insert into Medlem (Medlemsnummer, Namn, Telefon) values (3, 'Saddam', '260088'); insert into Medlem (Medlemsnummer, Namn, Telefon) values (4, 'Lotta', '174590'); insert into Medlem (Medlemsnummer, Namn, Telefon) values (1, 'Olle', '260088'); insert into Sektion (Sektionskod, Namn, Ledare) values ('A', 'Bowling', 4); insert into Sektion (Sektionskod, Namn, Ledare) values ('C', 'Simning', 2); insert into Sektion (Sektionskod, Namn, Ledare) values ('B', 'Kickboxing', 4); insert into Deltar (Medlem, Sektion) values (1, 'A'); insert into Deltar (Medlem, Sektion) values (1, 'B'); insert into Deltar (Medlem, Sektion) values (1, 'C'); insert into Deltar (Medlem, Sektion) values (2, 'C'); insert into Deltar (Medlem, Sektion) values (3, 'A');
select * from Anställd;
Nummer Namn Telefon Lön Chef Avdelning 2 Stina 2677 30000 0 H 3 Saddam 1088 22000 2 S 4 Lotta 4590 28000 2 H 1 Olle 2688 20000 3 S 8 Maria 2690 25000 4 C 9 Ulrik 2698 26000 8 C 10 Petter 2645 22000 8 C
select * from Avdelning;En enkel fråga: Visa vem som är chef för varje avdelning:
Avdelningskod Namn Ansvarig H Högkvarteret 2 S Säkerhet 3 C Data 8
select Avdelning.Namn, Anställd.NamnAggregatfunktioner: Genomsnittslönen för alla anställda
from Avdelning, Anställd
where Avdelning.Ansvarig = Anställd.Nummer;
Namn Namn Högkvarteret Stina Säkerhet Saddam Data Maria
select avg(Lön)Genomsnittslönen, uppdelat beroende på vem man har som chef (använd "group by"):
from Anställd;
AVG 24714
select Chef, avg(Lön)Genomsnittslönen, uppdelat på de olika avdelningarna
from Anställd
group by Chef;
Chef AVG 2 25000 3 20000 4 25000 8 24000 0 30000
select Avdelning, avg(Lön)Använd "where" för att begränsa vilka rader i tabellen som tas med när aggregatfunktionen beräknas:
from Anställd
group by Avdelning;
Avdelning AVG C 24333 H 29000 S 21000
select Avdelning, avg(Lön)Använd "having" för att begränsa vilka grupper (= rader i resultatet) som tas med:
from Anställd
where Lön > 20000
group by Avdelning;
Avdelning AVG C 24333 H 29000 S 22000
select Avdelning, avg(Lön)Man kan förstås kombinera "where" och "having":
from Anställd
group by Avdelning
having avg(Lön) > 22000;
Avdelning AVG C 24333 H 29000
select Avdelning, avg(Lön)
from Anställd
where Lön > 20000
group by Avdelning
having avg(Lön) > 22000;
Avdelning AVG C 24333 H 29000
select Namn, Lön, Namn, LönHelfiasko. Vi har inte talat om vad som är vad "i de två Anställd-tabellerna", och databashanteraren ger oss inte det svar vi hoppades på.
from Anställd, Anställd
where Chef = Nummer
and Lön > Lön;
Namn Lön Namn Lön
Om det hade varit två tabeller, en med de vanliga anställda (till exempel kallad proletär) och en med cheferna (till exempel kallad Chef), hade det varit enkelt att ställa frågan:
select proletär.Namn, proletär.Lön, Chef.Namn, Chef.LönGenom att införa två "alias" för samma tabell blir det precis som att jobba med två tabeller:
from proletär, Chef
where proletär.Chef = Chef.Nummer
and proletär.Lön > Chef.Lön;
select proletär.Namn, proletär.Lön, Chef.Namn, Chef.Lön
from Anställd as proletär, Anställd as Chef
where proletär.Chef = Chef.Nummer
and proletär.Lön > Chef.Lön;
Namn Lön Namn Lön Ulrik 26000 Maria 25000
create table Anställd (Nummer integer not null, Namn varchar(6), Telefon varchar(10), Lön integer, Chef integer, Avdelning character(1), primary key (Nummer)); create table Avdelning (Avdelningskod character(1) not null, Namn varchar(12), Ansvarig integer, primary key (Avdelningskod)); alter table Anställd add constraint Anställd_till_Chef foreign key (Chef) references Anställd (Nummer); alter table Anställd add constraint Anställd_till_Avdelning foreign key (Avdelning) references Avdelning (Avdelningskod); alter table Avdelning add constraint Avdelning_till_Ansvarig foreign key (Ansvarig) references Anställd (Nummer);
insert into Anställd (Nummer, Namn, Telefon, Lön, Avdelning) values (2, 'Stina', '2677', 30000, 'H'); insert into Anställd (Nummer, Namn, Telefon, Lön, Chef, Avdelning) values (3, 'Saddam', '1088', 22000, 2, 'S'); insert into Anställd (Nummer, Namn, Telefon, Lön, Chef, Avdelning) values (4, 'Lotta', '4590', 28000, 2, 'H'); insert into Anställd (Nummer, Namn, Telefon, Lön, Chef, Avdelning) values (1, 'Olle', '2688', 20000, 3, 'S'); insert into Anställd (Nummer, Namn, Telefon, Lön, Chef, Avdelning) values (8, 'Maria', '2690', 25000, 4, 'C'); insert into Anställd (Nummer, Namn, Telefon, Lön, Chef, Avdelning) values (9, 'Ulrik', '2698', 26000, 8, 'C'); insert into Anställd (Nummer, Namn, Telefon, Lön, Chef, Avdelning) values (10, 'Petter', '2645', 22000, 8, 'C'); insert into Avdelning (Avdelningskod, Namn, Ansvarig) values ('H', 'Högkvarteret', 2); insert into Avdelning (Avdelningskod, Namn, Ansvarig) values ('S', 'Säkerhet', 3); insert into Avdelning (Avdelningskod, Namn, Ansvarig) values ('C', 'Data', 8);