SQL. Underhållande pussel

Hej Habr!

I mer än 3 år har jag undervisat i SQL på olika utbildningscentra, och en av mina observationer är att eleverna behärskar och förstår SQL bättre om de får en uppgift, och inte bara pratar om möjligheterna och teoretiska grunder.

I den här artikeln kommer jag att dela med mig av min lista med uppgifter som jag ger eleverna som läxor och som vi genomför olika slags brainstorms på, vilket leder till en djup och tydlig förståelse av SQL.

SQL. Underhållande pussel

SQL (ˈɛsˈkjuˈɛl; eng. structured query language) är ett deklarativt programmeringsspråk som används för att skapa, modifiera och hantera data i en relationsdatabas som hanteras av ett lämpligt databashanteringssystem. Läs mer

Du kan läsa om SQL från olika källor.
Den här artikeln är inte avsedd att lära dig SQL från början.

Låt oss gå.

Vi kommer att använda det välkända HR-schema i Oracle med dess tabeller (Mer):

SQL. Underhållande pussel
Jag noterar att vi endast kommer att överväga uppgifter på SELECT. Det finns inga uppgifter på DML och DDL.

uppgifter

Begränsa och sortera data

Anställda bord. Få en lista med information om alla anställda
beslutet

SELECT * FROM employees

Anställda bord. Få en lista över alla anställda som heter 'David'
beslutet

SELECT *
  FROM employees
 WHERE first_name = 'David';

Anställda bord. Få en lista över alla anställda med job_id lika med 'IT_PROG'
beslutet

SELECT *
  FROM employees
 WHERE job_id = 'IT_PROG'

Anställda bord. Få en lista över alla anställda från 50:e avdelningen (department_id) med en lön (lön) större än 4000
beslutet

SELECT *
  FROM employees
 WHERE department_id = 50 AND salary > 4000;

Anställda bord. Få en lista över alla anställda från den 20:e och från den 30:e avdelningen (department_id)
beslutet

SELECT *
  FROM employees
 WHERE department_id = 20 OR department_id = 30;

Anställda bord. Få en lista över alla anställda vars sista bokstav i deras namn är "a"
beslutet

SELECT *
  FROM employees
 WHERE first_name LIKE '%a';

Anställda bord. Få en lista över alla anställda från 50:e och från 80:e avdelningen (department_id) som har en bonus (värdet i kolumnen commission_pct är inte tomt)
beslutet

SELECT *
  FROM employees
 WHERE     (department_id = 50 OR department_id = 80)
       AND commission_pct IS NOT NULL;

Anställda bord. Få en lista över alla anställda vars namn innehåller minst 2 bokstäver "n"
beslutet

SELECT *
  FROM employees
 WHERE first_name LIKE '%n%n%';

Anställda bord. Få en lista över alla anställda vars namn är längre än 4 bokstäver
beslutet

SELECT *
  FROM employees
 WHERE first_name LIKE '%_____%';

Anställda bord. Få en lista över alla anställda vars lön är mellan 8000 och 9000 (inklusive)
beslutet

SELECT *
  FROM employees
 WHERE salary BETWEEN 8000 AND 9000;

Anställda bord. Få en lista över alla anställda vars namn innehåller symbolen '%'
beslutet

SELECT *
  FROM employees
 WHERE first_name LIKE '%%%' ESCAPE '';

Anställda bord. Få en lista över alla chefs-ID:n
beslutet

SELECT DISTINCT manager_id
  FROM employees
 WHERE manager_id IS NOT NULL;

Anställda bord. Få en lista över anställda med deras positioner i formatet: Donald(sh_clerk)
beslutet

SELECT first_name || '(' || LOWER (job_id) || ')' employee FROM employees;

Använda enradsfunktioner för att anpassa utdata

Anställda bord. Få en lista över alla anställda vars namn är längre än 10 bokstäver
beslutet

SELECT *
  FROM employees
 WHERE LENGTH (first_name) > 10;

Anställda bord. Få en lista över alla anställda som har bokstaven 'b' i sitt namn (okänsligt för skiftlägen)
beslutet

SELECT *
  FROM employees
 WHERE INSTR (LOWER (first_name), 'b') > 0;

Anställda bord. Få en lista över alla anställda vars namn innehåller minst 2 bokstäver "a"
beslutet

SELECT *
  FROM employees
 WHERE INSTR (LOWER (first_name),'a',1,2) > 0;

Anställda bord. Få en lista över alla anställda vars lön är en multipel av 1000
beslutet

SELECT *
  FROM employees
 WHERE MOD (salary, 1000) = 0;

Anställda bord. Få det första 3-siffriga numret av den anställdes telefonnummer om hans nummer är i formatet ХХХ.ХХХ.ХХХХ
beslutet

SELECT phone_number, SUBSTR (phone_number, 1, 3) new_phone_number
  FROM employees
 WHERE phone_number LIKE '___.___.____';

Avdelningstabell. Få det första ordet från avdelningsnamnet för de med mer än ett ord i namnet
beslutet

SELECT department_name,
       SUBSTR (department_name, 1, INSTR (department_name, ' ')-1)
           first_word
  FROM departments
 WHERE INSTR (department_name, ' ') > 0;

Anställda bord. Få medarbetarnamn utan första och sista bokstaven i namnet
beslutet

SELECT first_name, SUBSTR (first_name, 2, LENGTH (first_name) - 2) new_name
  FROM employees;

Anställda bord. Få en lista över alla anställda vars sista bokstav i namnet är lika med 'm' och längden på namnet är större än 5
beslutet

SELECT *
  FROM employees
 WHERE SUBSTR (first_name, -1) = 'm' AND LENGTH(first_name)>5;

Dubbelt bord. Få datumet nästa fredag
beslutet

SELECT NEXT_DAY (SYSDATE, 'FRIDAY') next_friday FROM DUAL;

Anställda bord. Få en lista över alla anställda som har varit på företaget i över 17 år
beslutet

SELECT *
  FROM employees
 WHERE MONTHS_BETWEEN (SYSDATE, hire_date) / 12 > 17;

Anställda bord. Få en lista över alla anställda vars sista siffra i telefonnumret är udda och består av 3 nummer separerade med en punkt
beslutet

SELECT *
  FROM employees
 WHERE     MOD (SUBSTR (phone_number, -1), 2) != 0
       AND INSTR (phone_number,'.',1,3) = 0;

Anställda bord. Få en lista över alla anställda vars job_id-värde efter '_'-tecknet har minst 3 tecken, men detta värde efter '_' är inte lika med 'CLERK'
beslutet

SELECT *
  FROM employees
 WHERE     LENGTH (SUBSTR (job_id, INSTR (job_id, '_') + 1)) > 3
       AND SUBSTR (job_id, INSTR (job_id, '_') + 1) != 'CLERK';

Anställda bord. Få en lista över alla anställda genom att ersätta alla '.' i värdet PHONE_NUMBER på '-'
beslutet

SELECT phone_number, REPLACE (phone_number, '.', '-') new_phone_number
  FROM employees;

Använda konverteringsfunktioner och villkorliga uttryck

Anställda bord. Få en lista över alla anställda som kom till jobbet den första dagen i månaden (alla)
beslutet

SELECT *
  FROM employees
 WHERE TO_CHAR (hire_date, 'DD') = '01';

Anställda bord. Få en lista över alla anställda som kom till jobbet 2008
beslutet

SELECT *
  FROM employees
 WHERE TO_CHAR (hire_date, 'YYYY') = '2008';

DUBBLA bord. Visa morgondagens datum i formatet: Imorgon är det andra dagen i januari
beslutet

SELECT TO_CHAR (SYSDATE, 'fm""Tomorrow is ""Ddspth ""day of"" Month')     info
  FROM DUAL;

Anställda bord. Få en lista över alla anställda och deras startdatum i formatet: 21 juni 2007
beslutet

SELECT first_name, TO_CHAR (hire_date, 'fmddth ""of"" Month, YYYY') hire_date
  FROM employees;

Anställda bord. Få en lista över anställda med höjda löner med 20 %. Visa lön med dollartecken
beslutet

SELECT first_name, TO_CHAR (salary + salary * 0.20, 'fm$999,999.00') new_salary
  FROM employees;

Anställda bord. Få en lista över alla anställda som kom till jobbet i februari 2007.
beslutet

SELECT *
  FROM employees
 WHERE hire_date BETWEEN TO_DATE ('01.02.2007', 'DD.MM.YYYY')
                     AND LAST_DAY (TO_DATE ('01.02.2007', 'DD.MM.YYYY'));

SELECT *
  FROM employees
 WHERE to_char(hire_date,'MM.YYYY') = '02.2007'; 

DUBBLA bord. Exportera aktuellt datum, + sekund, + minut, + timme, + dag, + månad, + år
beslutet

SELECT SYSDATE                          now,
       SYSDATE + 1 / (24 * 60 * 60)     plus_second,
       SYSDATE + 1 / (24 * 60)          plus_minute,
       SYSDATE + 1 / 24                 plus_hour,
       SYSDATE + 1                      plus_day,
       ADD_MONTHS (SYSDATE, 1)          plus_month,
       ADD_MONTHS (SYSDATE, 12)         plus_year
  FROM DUAL;

Anställda bord. Få en lista över alla anställda med full lön (lön + commission_pct(%)) i formatet: $24,000.00 XNUMX
beslutet

SELECT first_name, salary, TO_CHAR (salary + salary * NVL (commission_pct, 0), 'fm$99,999.00') full_salary
  FROM employees;

Anställda bord. Få en lista över alla anställda och information om tillgängligheten av lönebonus (Ja/Nej)
beslutet

SELECT first_name, commission_pct, NVL2 (commission_pct, 'Yes', 'No') has_bonus
  FROM employees;

Anställda bord. Få lönenivån för varje anställd: Mindre än 5000 anses låg nivå, större än eller lika med 5000 och mindre än 10000 anses normal nivå, större än eller lika med 10000 anses hög nivå
beslutet

SELECT first_name,
       salary,
       CASE
           WHEN salary < 5000 THEN 'Low'
           WHEN salary >= 5000 AND salary < 10000 THEN 'Normal'
           ELSE 'High'
       END salary_level
  FROM employees;

Tabell för länder. För varje land, visa regionen där det är beläget: 1-Europa, 2-Amerika, 3-Asien, 4-Afrika (utan medlemskap)
beslutet

SELECT country_name country,
       DECODE (region_id,
               1, 'Europe',
               2, 'America',
               3, 'Asia',
               4, 'Africa',
               'Unknown')
           region
  FROM countries;

SELECT country_name
           country,
       CASE region_id
           WHEN 1 THEN 'Europe'
           WHEN 2 THEN 'America'
           WHEN 3 THEN 'Asia'
           WHEN 4 THEN 'Africa'
           ELSE 'Unknown'
       END
           region
  FROM countries;

Rapportera aggregerad data med hjälp av gruppfunktionerna

Anställda bord. Få en rapport per department_id med lägsta och maxlön, tidiga och sena ankomstdatum och antal anställda. Sortera efter antal anställda (desc)
beslutet

  SELECT department_id,
         MIN (salary) min_salary,
         MAX (salary) max_salary,
         MIN (hire_date) min_hire_date,
         MAX (hire_date) max_hire_Date,
         COUNT (*) count
    FROM employees
GROUP BY department_id
order by count(*) desc;

Anställda bord. Hur många anställda vars namn börjar på samma bokstav? Sortera efter kvantitet. Visa endast de där siffran är större än 1
beslutet

SELECT SUBSTR (first_name, 1, 1) first_char, COUNT (*)
    FROM employees
GROUP BY SUBSTR (first_name, 1, 1)
  HAVING COUNT (*) > 1
ORDER BY 2 DESC;

Anställda bord. Hur många anställda arbetar på samma avdelning och får samma lön?
beslutet

SELECT department_id, salary, COUNT (*)
    FROM employees
GROUP BY department_id, salary
  HAVING COUNT (*) > 1;

Anställda bord. Få en rapport över hur många anställda som anställdes varje dag i veckan. Sortera efter kvantitet
beslutet

SELECT TO_CHAR (hire_Date, 'Day') day, COUNT (*)
    FROM employees
GROUP BY TO_CHAR (hire_Date, 'Day')
ORDER BY 2 DESC;

Anställda bord. Få en rapport om hur många anställda som anställdes per år. Sortera efter kvantitet
beslutet

SELECT TO_CHAR (hire_date, 'YYYY') year, COUNT (*)
    FROM employees
GROUP BY TO_CHAR (hire_date, 'YYYY');

Anställda bord. Få antalet avdelningar som har anställda
beslutet

SELECT COUNT (COUNT (*))     department_count
    FROM employees
   WHERE department_id IS NOT NULL
GROUP BY department_id;

Anställda bord. Få lista över avdelnings-id med mer än 30 anställda
beslutet

  SELECT department_id
    FROM employees
GROUP BY department_id
  HAVING COUNT (*) > 30;

Anställda bord. Få en lista över avdelnings-id och den avrundade medellönen för anställda på varje avdelning.
beslutet

  SELECT department_id, ROUND (AVG (salary)) avg_salary
    FROM employees
GROUP BY department_id;

Tabell för länder. Få en lista över region_id summan av alla bokstäver i alla country_names där fler än 60
beslutet

  SELECT region_id
    FROM countries
GROUP BY region_id
  HAVING SUM (LENGTH (country_name)) > 60;

Anställda bord. Få en lista över avdelnings-id där anställda av flera (>1) jobb-id arbetar
beslutet

  SELECT department_id
    FROM employees
GROUP BY department_id
  HAVING COUNT (DISTINCT job_id) > 1;

Anställda bord. Få en lista över manager_id vars antal underordnade är större än 5 och summan av alla löner för hans underordnade är större än 50000
beslutet

  SELECT manager_id
    FROM employees
GROUP BY manager_id
  HAVING COUNT (*) > 5 AND SUM (salary) > 50000;

Anställda bord. Få en lista över manager_id vars genomsnittliga lön för alla hans underordnade är mellan 6000 och 9000 som inte får bonusar (commission_pct är tom)
beslutet

  SELECT manager_id, AVG (salary) avg_salary
    FROM employees
   WHERE commission_pct IS NULL
GROUP BY manager_id
  HAVING AVG (salary) BETWEEN 6000 AND 9000;

Anställda bord. Få maxlönen från alla anställda job_id som slutar med ordet "CLERK"
beslutet

SELECT MAX (salary) max_salary
  FROM employees
 WHERE job_id LIKE '%CLERK';

SELECT MAX (salary) max_salary
  FROM employees
 WHERE SUBSTR (job_id, -5) = 'CLERK';

Anställda bord. Få maxlönen bland alla medellöner för avdelningen
beslutet

  SELECT MAX (AVG (salary))
    FROM employees
GROUP BY department_id;

Anställda bord. Få antalet anställda med samma antal bokstäver i deras namn. Visa samtidigt endast de vars namn är längre än 5 och antalet anställda med samma namn är fler än 20. Sortera efter namnlängd
beslutet

  SELECT LENGTH (first_name), COUNT (*)
    FROM employees
GROUP BY LENGTH (first_name)
  HAVING LENGTH (first_name) > 5 AND COUNT (*) > 20
ORDER BY LENGTH (first_name);

  SELECT LENGTH (first_name), COUNT (*)
    FROM employees
   WHERE LENGTH (first_name) > 5
GROUP BY LENGTH (first_name)
  HAVING COUNT (*) > 20
ORDER BY LENGTH (first_name);

Visa data från flera tabeller med Joins

Tabellanställda, avdelningar, platser, länder, regioner. Få en lista över regioner och antalet anställda i varje region
beslutet

  SELECT region_name, COUNT (*)
    FROM employees e
         JOIN departments d ON (e.department_id = d.department_id)
         JOIN locations l ON (d.location_id = l.location_id)
         JOIN countries c ON (l.country_id = c.country_id)
         JOIN regions r ON (c.region_id = r.region_id)
GROUP BY region_name;

Tabellanställda, avdelningar, platser, länder, regioner. Få detaljerad information om varje anställd:
Förnamn, Efternamn, Avdelning, Jobb, Gata, Land, Region
beslutet

SELECT First_name,
       Last_name,
       Department_name,
       Job_id,
       street_address,
       Country_name,
       Region_name
  FROM employees  e
       JOIN departments d ON (e.department_id = d.department_id)
       JOIN locations l ON (d.location_id = l.location_id)
       JOIN countries c ON (l.country_id = c.country_id)
       JOIN regions r ON (c.region_id = r.region_id);

Anställda bord. Visa alla chefer som har fler än 6 anställda
beslutet

  SELECT man.first_name, COUNT (*)
    FROM employees emp JOIN employees man ON (emp.manager_id = man.employee_id)
GROUP BY man.first_name
  HAVING COUNT (*) > 6;

Anställda bord. Visa alla anställda som inte rapporterar till någon
beslutet

SELECT emp.first_name
  FROM employees  emp
       LEFT JOIN employees man ON (emp.manager_id = man.employee_id)
 WHERE man.FIRST_NAME IS NULL;

SELECT first_name
  FROM employees
 WHERE manager_id IS NULL;

Anställda tabell, Job_history. Medarbetartabellen lagrar alla anställda. Tabellen Job_history lagrar anställda som lämnat företaget. Få en rapport om alla anställda och deras status i företaget (Anställd eller lämnat företaget med avgångsdatum)
Exempel:
förnamn | status
jennifer | Lämnade företaget den 31 december 2006
Clara | Arbetar för närvarande
beslutet

SELECT first_name,
       NVL2 (
           end_date,
           TO_CHAR (end_date, 'fm""Left the company at"" DD ""of"" Month, YYYY'),
           'Currently Working')
           status
  FROM employees e LEFT JOIN job_history j ON (e.employee_id = j.employee_id);

Tabellanställda, avdelningar, platser, länder, regioner. Få en lista över anställda som bor i Europa (region_name)
beslutet

 SELECT first_name
  FROM employees
       JOIN departments USING (department_id)
       JOIN locations USING (location_id)
       JOIN countries USING (country_id)
       JOIN regions USING (region_id)
 WHERE region_name = 'Europe';
 
 SELECT first_name
  FROM employees  e
       JOIN departments d ON (e.department_id = d.department_id)
       JOIN locations l ON (d.location_id = l.location_id)
       JOIN countries c ON (l.country_id = c.country_id)
       JOIN regions r ON (c.region_id = r.region_id)
 WHERE region_name = 'Europe';

Bordsanställda, avdelningar. Visa alla avdelningar med fler än 30 anställda
beslutet

SELECT department_name, COUNT (*)
    FROM employees e JOIN departments d ON (e.department_id = d.department_id)
GROUP BY department_name
  HAVING COUNT (*) > 30;

Bordsanställda, avdelningar. Visa alla anställda som inte finns på någon avdelning
beslutet

SELECT first_name
  FROM employees  e
       LEFT JOIN departments d ON (e.department_id = d.department_id)
 WHERE d.department_name IS NULL;

SELECT first_name
  FROM employees
 WHERE department_id IS NULL;

Bordsanställda, avdelningar. Visa alla avdelningar utan anställda
beslutet

SELECT department_name
  FROM employees  e
       RIGHT JOIN departments d ON (e.department_id = d.department_id)
 WHERE first_name IS NULL;

Anställda bord. Visa alla anställda som inte har några underordnade
beslutet

SELECT man.first_name
  FROM employees  emp
       RIGHT JOIN employees man ON (emp.manager_id = man.employee_id)
 WHERE emp.FIRST_NAME IS NULL;

Tabellanställda, jobb, avdelningar. Visa anställda i formatet: First_name, Job_title, Department_name.
Exempel:
förnamn | jobbtitel | Avdelningsnamn
Donald | frakt | Kontorist Frakt
beslutet

SELECT first_name, job_title, department_name
  FROM employees  e
       JOIN jobs j ON (e.job_id = j.job_id)
       JOIN departments d ON (d.department_id = e.department_id);

Anställda bord. Få en lista över anställda vars chefer fick jobb 2005, men samtidigt fick dessa arbetare själva jobb före 2005
beslutet

SELECT emp.*
  FROM employees emp JOIN employees man ON (emp.manager_id = man.employee_id)
 WHERE     TO_CHAR (man.hire_date, 'YYYY') = '2005'
       AND emp.hire_date < TO_DATE ('01012005', 'DDMMYYYY');

Anställda bord. Få en lista över anställda vars chefer fick jobb i januari månad något år och längden på jobbtiteln för dessa anställda är mer än 15 tecken
beslutet

SELECT emp.*
  FROM employees  emp
       JOIN employees man ON (emp.manager_id = man.employee_id)
       JOIN jobs j ON (emp.job_id = j.job_id)
 WHERE TO_CHAR (man.hire_date, 'MM') = '01' AND LENGTH (j.job_title) > 15;

Använda underfrågor för att lösa frågor

Anställda bord. Få en lista över anställda med det längsta namnet.
beslutet

SELECT *
  FROM employees
 WHERE LENGTH (first_name) =
       (SELECT MAX (LENGTH (first_name)) FROM employees);

Anställda bord. Få en lista över anställda med en lön som är högre än genomsnittslönen för alla anställda.
beslutet

SELECT *
  FROM employees
 WHERE salary > (SELECT AVG (salary) FROM employees);

Tabellanställda, avdelningar, platser. Få den stad där anställda tjänar minst totalt.
beslutet

SELECT city
    FROM employees e
         JOIN departments d ON (e.department_id = d.department_id)
         JOIN locations l ON (d.location_id = l.location_id)
GROUP BY city
  HAVING SUM (salary) =
         (  SELECT MIN (SUM (salary))
              FROM employees e
                   JOIN departments d ON (e.department_id = d.department_id)
                   JOIN locations l ON (d.location_id = l.location_id)
          GROUP BY city);

Anställda bord. Få en lista över anställda vars chef får en lön på mer än 15000 XNUMX.
beslutet

SELECT *
  FROM employees
 WHERE manager_id IN (SELECT employee_id
                        FROM employees
                       WHERE salary > 15000)

Bordsanställda, avdelningar. Visa alla avdelningar utan anställda
beslutet

SELECT *
  FROM departments
 WHERE department_id NOT IN (SELECT department_id
                               FROM employees
                              WHERE department_id IS NOT NULL);

Anställda bord. Visa alla anställda som inte är chefer
beslutet

SELECT *
  FROM employees
 WHERE employee_id NOT IN (SELECT manager_id
                             FROM employees
                            WHERE manager_id IS NOT NULL)

Anställda bord. Visa alla chefer som har fler än 6 anställda
beslutet

SELECT *
  FROM employees e
 WHERE (SELECT COUNT (*)
          FROM employees
         WHERE manager_id = e.employee_id) > 6;

Bordsanställda, avdelningar. Visa medarbetare som arbetar på IT-avdelningen
beslutet

SELECT *
  FROM employees
 WHERE department_id = (SELECT department_id
                          FROM departments
                         WHERE department_name = 'IT');

Tabellanställda, jobb, avdelningar. Visa anställda i formatet: First_name, Job_title, Department_name.
Exempel:
förnamn | jobbtitel | Avdelningsnamn
Donald | frakt | Kontorist Frakt
beslutet

SELECT first_name,
       (SELECT job_title
          FROM jobs
         WHERE job_id = e.job_id)
           job_title,
       (SELECT department_name
          FROM departments
         WHERE department_id = e.department_id)
           department_name
  FROM employees e;

Anställda bord. Få en lista över anställda vars chefer fick jobb 2005, men samtidigt fick dessa arbetare själva jobb före 2005
beslutet

SELECT *
  FROM employees
 WHERE     manager_id IN (SELECT employee_id
                            FROM employees
                           WHERE TO_CHAR (hire_date, 'YYYY') = '2005')
       AND hire_date < TO_DATE ('01012005', 'DDMMYYYY');

Anställda bord. Få en lista över anställda vars chefer fick jobb i januari månad något år och längden på jobbtiteln för dessa anställda är mer än 15 tecken
beslutet

SELECT *
  FROM employees e
 WHERE     manager_id IN (SELECT employee_id
                            FROM employees
                           WHERE TO_CHAR (hire_date, 'MM') = '01')
       AND (SELECT LENGTH (job_title)
              FROM jobs
             WHERE job_id = e.job_id) > 15;

Det var allt tills vidare.

Jag hoppas att uppgifterna var intressanta och spännande.
Jag kommer att lägga till den här listan så mycket som möjligt.
Jag kommer också att vara glad för alla kommentarer och förslag.

PS: Om någon kommer på en intressant uppgift på SELECT, skriv i kommentarerna, jag lägger till den i listan.

Tack.

Källa: will.com

Lägg en kommentar