Upload
malin-johansson
View
254
Download
2
Embed Size (px)
Citation preview
www.artofit.se 2010-10-27 2
Kursens mål • Relationsdatabaser:
– datamodell – tabeller – relationer
• SQL-frågor:– sökningar– manipulering av data– databasobjekt– behörighet
www.artofit.se 2010-10-27 3
Begrepp i en relationsdatabas
• Databas = samling av tabeller• DBMS – databashanterare
- Oracle, SQL server, My SQL
• Tabeller• Kolumner (fält)• Rader (poster)• Primär nyckel (PK)• Främmande nyckel (FK)• Relationer
www.artofit.se 2010-10-27 4
Relationer• Varje tabell har ett unikt namn• Ordningen på kolumner i en tabell
saknar betydelse• Ordningen på rader i en tabell
saknar betydelseTabeller relaterar till varandra• Kolumner i två tabeller har samma
värde• Constraints som bestämmer regler för
relationen– Primary Key, PK: identifierar alla
poster unikt i en tabell. Består av en eller flera kolumner
– Foreign Key. FK: Kontrollerar att det inlagda värdet finns i den relaterade primärnyckeln
KundKundnrNamnAdressTelefonnr
OrderOrdernrDatumSäljareOrderdetaljerkundnr
www.artofit.se 2010-10-27 5
Relationer forts.
Typer av förhållanden:• Ett-till-ett (1:1)• Ett-till-många (1:M)• Många-till många (M:M)
KundKundnrNamnAdressTelefonnr
OrderOrdernrDatumSäljareOrderdetaljerkundnr
www.artofit.se 2010-10-27 6
Datatyper• Number numeriska värden (tal)• Varchar2 tecken• Boolean booleskt värde (0=falskt, 1=sant)• Date datum• Timestamp tidsstämpel
CAST(uttryck AS datatyp): omvandlar ett uttryck från en datatyp till en annan
www.artofit.se 2010-10-27 7
Databasutveckling
1.Kravanalys2.Konceptuell modell3.Logisk modell4.Normalisering5.Fysisk datamodell
OBS! Dålig fysisk design är kostsamt och mycket svårt att korrigera
www.artofit.se 2010-10-27 8
NormaliseringTar bort redundans (dubbellagring) i databasen
Första NF (normalformen)1. Varje kolumn i tabellen är unik2. Data i ett kolumnfält innehåller bara ett
värde3. Alla värden i en kolumn skall vara av
samma datatypAndra NF
4. Varje rad i en tabell är unik och beronde av PK
Tredje NF5. Fält som inte är nycklar skall kunnas
härledas till varandra.
www.artofit.se 2010-10-27 9
Introduktion till SQL
• Standard SQL ANSI• Standard 1987 ISO (1992,1999)• SQL är det första och hittills enda relationsdatabas
språket som är internationellt accepterat• SQL kan användas– Interaktivt, t ex med SQL Developer eller SQL*Plus– Inbäddat i ”valfritt” programmeringsspråk
OBS! Oracle används som DBMS i denna kurs
www.artofit.se 2010-10-27 10
SQL• SQL kan användas för att– Söka efter data– Lägga in, uppdatera och ta bort en rad i en tabell– Skapa, ersätta, uppdatera och ta bort objekt– Ge och ta bort rättigheter till objekt
• SQL är ett frågespråk, inte ett proceduellt språk• Är inte känsligt för – gemener/versaler• Notera att själva datat i tabellerna är det.
– Radbrytningar, mellanslag eller tabbar
www.artofit.se 2010-10-27 11
Gruppering av SQL kommandon
• Data Manipulation Language commands (DML)– Select, Insert, Update, Delete
• Select brukar definieras som Query Language• Data Definition Language commands (DDL)
– create table, alter view, drop column• Data Control Language commands (DCL)
– Grant, revoke
www.artofit.se 2010-10-27 12
SQL frågor
• SQL är mycket flexibelt och har en speciell syntax• Du kan ställa frågor till en databas på ett oändligt antal sätt• Du kan ställa frågor på olika sätt och få samma resultat• Du kan ställa en fråga på fel sätt och inte få något svar alls• Du kan ställa en fråga på fel sätt och få svar på en fråga du inte
insåg att du frågade
www.artofit.se 2010-10-27 13
SELECT – Hämta data• Hämtar data från databasen• Består av minst 2 delar:
- SELECT kolumner FROM tabeller
• Att skriva en fråga, se datamodell:1. Vilka tabeller?2. Vilka kolumner?
www.artofit.se 2010-10-27 14
Välj alla kolumner
SELECT * FROM employees;
• Asterixen (*) visar samtliga rader och samtliga kolumner i den ordning som de lagras i tabellen
www.artofit.se 2010-10-27 15
Välj en speciell kolumn
SELECT first_name FROM employees;
• Visar samtliga rader i tabellen för den namngivna kolumnen
www.artofit.se 2010-10-27 16
Välj flera kolumner
SELECT first_name, last_name, email FROM employees;
• Samtliga rader visas för varje vald kolumn• Kallas även PROJEKTION• Separera kolumnnamn med kommatecken(,)• Ordningsföljden på kolumnerna i frågan bestämmer i vilken ordning
kolumnerna visas i resultatet
www.artofit.se 2010-10-27 17
WHERE – Filtrera data• Begränsar antalet rader som hämtas• Består av minst 3 delar:
- SELECT kolumner FROM tabeller WHERE villkor
• Att skriva en fråga, se datamodell:1. Vilka tabeller?2. Vilka kolumner?3. Vilket villkor?
www.artofit.se 2010-10-27 18
Lika med =
SELECT first_name, last_name FROM employees WHERE first_name = 'David';
• Tecken omges av enkelfnuttar ’tecken’ • SQL är känslig för gemener och versaler när man
jämför text.
SELECT first_name, last_name FROM employees WHERE salary = 3200;
• Kolumnen som man testar på behöver inte vara med i SELECT-satsen
www.artofit.se 2010-10-27 19
Ej lika med != eller <>
SELECT first_name, last_name FROM employees WHERE first_name <> 'David';
• Tecken omges av enkelfnuttar ’tecken’ • SQL är känslig för gemener och versaler när man
jämför text.
SELECT first_name, last_name FROM employees WHERE salary != 3200;
• Kolumnen som man testar på behöver inte vara med i SELECT-satsen
www.artofit.se 2010-10-27 20
Större än och Mindre än• Större än >• Större än eller lika med >=• Mindre än <• Mindre än eller lika med <=
SELECT first_name, last_name, salary FROM employees WHERE salary <= 3200;
www.artofit.se 2010-10-27 21
Intervall: BETWEEN och NOT BETWEEN• Större än eller lika med ett värde
och mindre än eller lika med ett annat värde- BETWEEN lägsta värde AND högsta värde
SELECT first_name, last_name, salary FROM employees WHERE salary BETWEEN 2100 AND 2700;
• Inkluderar värdena som anger intervallet i resultatet• Mest användbart för tal och datum
www.artofit.se 2010-10-27 22
Mönstermatchning: LIKE och NOT LIKE• Matchar följande mönster LIKE
- noll eller flera tecken %- ett tecken _
SELECT first_name, last_name FROM employees WHERE first_name LIKE 'S%';
SELECT first_name, last_name FROM employees WHERE first_name LIKE '_d%';
www.artofit.se 2010-10-27 23
Lista: IN och NOT IN
• Lika med något av flera värden i en listaIN(värde1, värde2, värde3…)Värdena separeras med komma , och omsluts av parantes (värden)
SELECT job_title, max_salary FROM jobs WHERE job_title IN ('President', 'Accountant',
'Stock Clerk');
SELECT job_title, max_salary FROM jobs WHERE max_salary NOT IN (40000, 9000, 5000);
www.artofit.se 2010-10-27 24
Lista forts. ANY, SOME, ALL
Jämförelse av listvärden med <, <=, >, >=, = eller <> • ANY och SOME har samma funktion och är sant om något av värdena i
listan är sanna, = (samma som IN)SELECT job_title, salary FROM jobs WHERE salary > ANY (40000, 9000, 5000);
• ALL är sant om alla värden i listan överenstämmer med villkoret, <> (samma som NOT IN)
SELECT job_title, salary FROM jobs WHERE salary > ALL (3000, 5000, 9000);
www.artofit.se 2010-10-27 25
Värde saknas:IS NULL och IS NOT NULL • NULL betyder att värdet är okänt, saknas eller är ej användbart• Ej samma som talet 0 som är ett värde• Kan inte jämföras med andra värden, använd ej =
NULL-värden måste kontrolleras var för sig • Kontrolleras med IS NULL och IS NOT NULL
SELECT first_name, last_name, manager_id FROM employees WHERE manager_id IS NULL;
www.artofit.se 2010-10-27 26
Sammansatta villkor:AND och OR• Man grupperar villkor med AND och OR
- AND begränsar urvalet ytterligare- OR utökar urvalet ytterligare
• Man kan kombinera ihop hur många villkor man vill i WHERE-satsen• AND utvärderas alltid före OR
- använd alltid paranteser ( ) för att styra utvärderingsordningen
SELECT first_name, last_name, manager_id FROM employees WHERE first_name LIKE 'D%' AND (last_name LIKE 'G%'
OR last_name LIKE 'B%');
www.artofit.se 2010-10-27 27
ORDER BY – Sortera data• Sorterar rader som hämtas• Består av minst 3 delar:
- SELECT kolumner FROM tabeller WHERE villkor ORDER BY kolumner
• Att skriva en fråga, se datamodell:1. Vilka tabeller?2. Vilka kolumner?3. Vilket villkor?4. Sorteringskolumner?
www.artofit.se 2010-10-27 28
Sortera
SELECT last_name, first_name, manager_id FROM employees WHERE manager_id = 145ORDER BY last_name DESC, first_name;
• ORDER BY anges efter eventuell WHERE-sats• Sorteringsordningen bestäms av ordningen på
kolumnerna- 1:a kolumn=1:a sortering, 2:a kolumn=2:a sortering osv
• Stigande sortering (ASC) är standard och anges ej: A-Z, 1-100
• Fallande sortering fås genom att skriva DESC efter kolumnnamnet
www.artofit.se 2010-10-27 29
forts. Sortera
SELECT last_name, first_name, manager_id FROM employees WHERE manager_id = 145ORDER BY 1 DESC, 2;
• Istället för kolumnnamn kan man ange sekvensnumret i SELECT-satsen:- 2 anger 2:a kolumnen i SELECT-satsen, i detta fall first_name
www.artofit.se 2010-10-27 30
Alias för kolumner
• Används för att ge en kolumn ett annat namn än kolumn-namnet i tabellen
• Kan göra resultatet mer lättläst• Det finns olika sätt att ange alias, se exempel
SELECT first_name första, first_name "Första namn",
first_name AS "Förnamn" FROM employees;
• Om kolumnalias innehåller specialtecken måste alias anges inom dubbelfnuttar ”alias”
www.artofit.se 2010-10-27 31
UNION och UNION ALL
• UNION och UNION ALL visar all data som finns i de båda dataseten.• UNION tar bort dubletter• UNION ALL tar med dubletter• Varje SELECT måste ha samma antal kolumner• Matchande kolumner måste ha samma datatyp• Använd kolumnposition vid sortering
SELECT first_name, last_name, manager_id FROM employees UNIONSELECT first_name, last_name, teacher_id FROM studentsORDER BY 3;
DS1 DS2
www.artofit.se 2010-10-27 32
MINUS och INTERSECT• MINUS tar bort data från dataset1 som finns i dataset2• Ange den kolumn du vill subtrahera på först i
SELECT-satsen
SELECT manager_id FROM employees MINUSSELECT teacher_id FROM students
• INTERSECT visar data som är gemensamt för dataset1 som finns i dataset2
SELECT manager_id FROM employees INTERSECTSELECT teacher_id FROM students
DS1 DS2
DS1 DS2
www.artofit.se 2010-10-27 33
Funktionerhttp://download.oracle.com/docs/cd/B19306_01/server.102/b14200/functions001.htm
• Används för att omvandla data till något annat än det som lagras i databasen, t ex:– ändra värden– kombinera värden för att skapa nya– ändra värdens format
• Kan användas i alla typer av frågor• Kan användas i både SELECT-, WHERE- och ORDER BY-satsen• Funktionstyper:
– Individuella: varje rad utvärderas var för sig– Gruppfunktioner: ett antal rader utvärderas samtidigt
• Format:– funktionsnamn(argument) ex. LENGTH(last_name)– funktionsnamn(arg1,arg2,arg3…argN) ex. SUBSTR(email, 1, 4)
www.artofit.se 2010-10-27 34
Text-funktioner• LOWER(email) – ändrar alla tecken i strängen till gemener • UPPER(first_name) – ändrar alla tecken i strängen till versaler• INITCAP(last_name) – omvandlar första bokstaven i ordet till en versal• LPAD(last_name, 20, ‘*‘) lägger till *:or till vänster så att strängen blir
20 tkn lång• RPAD(last_name, 20, ‘*‘) lägger till *:or till höger så att strängen blir 20
tkn lång • LTRIM(salary, ‘0’) – tar bort 0:or i slutet av strängen• RTRIM(salary, ‘0’) – tar bort 0:or i början av strängen• SUBSTR(email, 1, 4) – visar 4 tecken i strängen räknat från 1:a tecknet • LENGTH(last_name) – räknar ut antal tecken i strängen• REPLACE(first_name, ‘Steven’, ‘Steve’) – ersätter Steven med Steve• CONCAT(first_name, last_name) eller || - slår ihop två strängar till en• TO_NUMBER(‘23123’) – omvandlar tecknen 23123 till numeriska värdet • TO_DATE( ‘20101213’, ‘YYYY-MM-DD’) – omvandlar till datum 2010-12-13
www.artofit.se 2010-10-27 35
Numeriska-funktioner
• ABS(-2) ger absoluta vädret av talet(alltid ett positivt värde)
• SIGN(salary) returnerar 1 för positiva värden -1 för negativa och 0 för noll
• MOD(salary, 7) returnerar resten av divisionen salary/7. Dividera med 2 för att kontrollera om värdet är udda eller jämnt.
• ROUND(salary, 0) avrundar salary till närmaste heltal(utan decimal)
• TRUNC(salary, 0) hugger av salary till närmaste heltal(avrundar alltid nedåt)
• Operatorer +, - * och / kan användas i SQL
www.artofit.se 2010-10-27 36
Datum-funktioner
• ADD_MONTHS(hire_date, 5) - adderar 5 månader till hire_date
• MONTHS_BETWEEN(sysdate, hire_date) - beräknar antal månader mellan hire_date och sysdate
• LAST_DAY(sysdate)- anger sista dagen i månaden• SYSDATE - anger aktuell tid i databasen • TRUNC- returnerar datum utan tidsangivelse• ROUND(sysdate, ‘format’) - avrundar datum till angivet format• TO_CHAR(sysdate, ‘format’) - omvandlar datum till tecken eller numeriskt värde
www.artofit.se 2010-10-27 37
Formatmask DatumTO_CHAR(datum, ’datumformat’)
• YYYY Fyrasiffrigt år 2010• YEAR År TWENTY TEN• RR Två siffror sekel 10• MM Tvåsiffrig månad 11• MON Trebokstavs-förkortning månad NOV• MONTH Månad i versaler NOVEMBER• Month Månad November• DD Numerisk dag 03• DAY Veckodag Onsdag• DY Tvåbokstavs-förkortning veckodag On• D Dag i veckan, söndag=1 3• HH el. HH12 Timmar (00-12) 01• HH24 Timmar (00-23) 13• MI Minuter 03• SS Sekunder 45• AM el PM Förmiddag/eftermiddag PM• WW Vecka på året 44• Q Kvartal på året 4
www.artofit.se 2010-10-27 38
NVL-funktionerGer en riktig behandling av NULL-värdet, utan NVL blir addition med NULL
alltid NULL.• NVL(arg1, arg2)
- arg1 är kolumnnamnet, om arg1 inte är NULL ger NVL dess värde- om arg1 är NULL ges värdet på arg 2
SELECT last_name, salary * NVL(commission_pct, 0) +
salary FROM employees;
• COLAECHE(exp1, exp2, exp3) – visar första värdet från vänsters som ej är null
• NVL2(exp, if null, if not null) – testar om exp är null och anger värdet• NULLIF(exp1, exp2) anger null om exp1=exp2
www.artofit.se 2010-10-27 39
Övriga funktioner• DECODE(jobid, ’IT_PROG’, ’PROGRAMMERARE’, ’ADM’)
- Om jobid= ’IT_PROG’ så ’IT’ annars ’ADM’)• CASE
WHEN salary > 0 THEN salary*0.04ELSE 0
END - Om salary >0 så salary*0.04 annars 0
• CASE salaryWHEN 2900 THEN salary*0.04WHEN 0 = 0 THEN 0ELSE null
END - Om salary=2900 så salary*0.04, om salary=0 så 0 annars null
www.artofit.se 2010-10-27 40
Gruppfunktioner
• Ger ett resultat för ett antal rader• Kan användas för alla numeriska värden• Vissa fungerar även på text och datum• MIN, MAX och COUNT fungerar med alla datatyper• COUNT DISTINCT visar antal unika värden i en kolumn• AVG kan endast användas på numeriska värden
SELECT AVG (salary) FROM employees;
www.artofit.se 2010-10-27 41
Gruppfunktioner
• SUM(salary) summerar salary
• COUNT(employee_id) räknar antalet employee_id:n
• MAX(salary) visar högsta salary
• MIN(salary) visar lägsta salary
www.artofit.se 2010-10-27 42
Gruppfunktioner begränsningar• Du kan INTE välja att få enstaka och gruppresultat tillsammans:
SELECT first_name, last_name, MIN (salary) FROM employees;
– Denna sats ger ett felmeddelande– Du måste gruppera de enstaka resultaten (first_name och
last_name) för att sqlsatsen ska fungera. Detta ger dock inte önskat resultat.
www.artofit.se 2010-10-27 43
GruppfunktionerGROUP BY• Används för att gruppera resultatet
SELECT department_id, COUNT (employee_id) FROM employees GROUP BY department_id;
www.artofit.se 2010-10-27 44
GruppfunktionerHAVING• Används för att filtrera GROUP BY resultat• Alias kan ej användas på kolumnnamnen vid HAVING
SELECT department_id, COUNT (employee_id) FROM employees GROUP BY department_idHAVING COUNT(employee_id) > 5;
www.artofit.se 2010-10-27 45
Frågor mot flera tabeller
EmployeesEmployee_idFirst_nameLast_nameDepartment_idManager_id
DepartmentsDepartment_idDepartment_nameManager_id
• JOINS används för att kombinera kolumner från en eller flera tabeller
www.artofit.se 2010-10-27 46
Att skriva JOINS
• Att skriva en join, se datamodell:1. Vilka kolumner vill du se?2. Vilka tabeller finns kolumnerna i?3. Vilka gemensamma kolumner har dessa tabeller?4. Vilken relation har dessa tabeller(1:1, 1:n eller n:n)?
• Använd alias för tabellnamn
SELECT first_name, last_name, department_name, e.department_id
FROM employees e, departments d WHERE e.department_id = d.department_id AND department_name LIKE 'IT';
www.artofit.se 2010-10-27 47
Jointyper
• EQUIJOIN (INNER JOIN)– WHERE e.department_id = d.department_idOm du glömmer att ange villkoret mellan tabellerna får
du en ”Cartesian product”, dvs du får alla raderna från båda tabellerna
• OUTER JOIN– WHERE e.department_id(+) = d.department_idDet är tabellen som kan sakna värden som skall ha + -
tecknet
• SELF-JOIN– SELECT e.last_name employee, m.last_name manager
FROM employees e, employees m WHERE e.manager_id = m.employee_id;
www.artofit.se 2010-10-27 48
EQUIJOIN (INNER JOIN)
• Hämtar värden från två eller flera tabeller där kolumnvärdena matchar.
• Specificera i SELECT från vilken tabell kolumnvärdet skall hämtas. SELECT e.last_name, d.department_name FROM employees e, departments d WHERE e.department_id = d.department_id;
• Om du glömmer WHERE-villkoret får du en ”Cartesian product”, alla rader i ena tabellen matchas mot alla rader i den andra tabellen.
www.artofit.se 2010-10-27 49
OUTER JOIN
• När du vill se alla värden från en tabell och de värden från en annan tabell som matchar.
SELECT d.department_name, e.last_name FROM departments d, employees e WHERE d.department_id = e.department_id(+);
• (+) –tecknet sätts på den tabell som kan sakna matchande värden
• När värde saknas returneras NULL
www.artofit.se 2010-10-27 50
SELF JOIN
• Används när en tabell refererar sig själv• Måste använda alias för tabellen i FROM-satsen
SELECT e.employee_id AS employeeid, e.last_name AS employee, m.employee_id AS managerid, m.last_name AS manager FROM employees e, employees mWHERE e.manager_id = m.employee_id;
www.artofit.se 2010-10-27 51
Subfrågor
• En fråga som ställs i WHERE satsen• Resultatet av subfrågan används för att lösa huvudfrågan
SELECT department_id, last_name FROM employees WHERE department_id = (SELECT department_id FROM employees WHERE
employee_id = 121);
• Går att nästla obegränsat antal frågor• Subfrågan kan innehålla tabeller som inte finns i huvudfrågan• Subfrågan kan inte innehålla ORDER BY
www.artofit.se 2010-10-27 52
Databehandling
• Data Manipulation Language(DML)– INSERT: lägga till data– UPDATE: ändra data– DELETE: ta bort data
www.artofit.se 2010-10-27 53
INSERT- Lägg till data
INSERT INTO employees (employee_id, last_name, first_name, email,
hire_date, job_id, salary)VALUES (10000, 'Hult', 'Nisse', '[email protected]',
'2002-10-19', 'IT_PROG', 5000);
• Använd DESCRIBE för att visa kolumntyp och ordningsföljd• Värden skiljs åt med komma• Värdet måste vara av rätt datatyp• Tecken- och Datumsträngar skall vara inom apostrofer• Kolumn som inte anges i INSERT får värdet NULL• Använd SYSDATE för registrering av dagens datum
www.artofit.se 2010-10-27 54
UPDATE – Ändra data
UPDATE employees SET last_name = 'Hulten', first_name = 'Nils' WHERE employee_id = 10000;
• GLÖM INTE WHERE-satsen!!! Annars uppdateras samtliga poster
• Testa WHERE-villkoret i en SELECT-sats först!!!
www.artofit.se 2010-10-27 55
DELETE – Ta bort data
DELETE FROM employeesWHERE employee_id = 10000;
• GLÖM INTE WHERE-satsen!!! Annars uppdateras samtliga poster
• Testa WHERE-villkoret i en SELECT-sats först!!!• Om du vill ta bort ett värde från en kolumn, sätt värdet
till NULL med UPDATE-kommando
www.artofit.se 2010-10-27 56
TRANSAKTIONER
• Är ändringar som utförs mellan två COMMIT• Antingen sparas hela transaktionen genom COMMIT
eller inget av transaktionen genom ROLLBACK.
• Vid systemfel i en transaktion görs en ROLLBACK automatiskt
www.artofit.se 2010-10-27 57
COMMIT
• Används för att göra INSERT, UPDATE och DELETE permanenta i databasen.
COMMIT;
www.artofit.se 2010-10-27 58
ROLLBACK
• Tar bort alla förändring till senast COMMIT genom att rulla tillbaka arbetet
ROLLBACK;
www.artofit.se 2010-10-27 59
Objekt
• Tabell• Constraints – kolumnregler NOT NULL, PRIMARY KEY, FOREIGN KEY osv
• Index – används för att snabba upp sökningar i databasen• Vy – virtuell tabell som inte innehåller data• Sekvenser – räknare som automatiskt ger unika värdem
www.artofit.se 2010-10-27 60
Index
• Sorterar datat i en eller flera kolumner– Snabbare sökning än i tabellen där datat ligger i en slumpmässig
ordning• Obegränsat antal index på en tabell
– Många index gör att Insert, Update och Delete kommandon tar längre tid
– Uppdateras automatiskt när tabellen uppdateras• Påverkar inte SQL syntaxen• En Primary Key skapar ett unikt index
www.artofit.se 2010-10-27 61
Vyer
• En virtuell tabell• Har inget eget data• En SELECT-sats där reultatet blir en tabell• Kan inte använda ORDER BY i SELECT-satsen vid skapande av vyn• Under vissa förhållanden går det att uppdatera en underliggande tabell
www.artofit.se 2010-10-27 62
Behörighet
• Skapa användare:– CREATE USER nisse IDENTIFIED BY hult;
• Ändra lösenord:– ALTER USER nisse IDENTIFIED BY sten;
• Tilldela användare rättigheter– GRANT CONNECT TO nisse;
• Ta bort rättigheter:– REVOKE CONNECT FROM nisse;
• Ta bort användare:– DELETE USER nisse;
www.artofit.se 2010-10-27 63
FRÅGOR ?
www.artofit.se 2010-10-27 64