You are on page 1of 26

Обединување на табели.

Внатрешни
и надворешни обединување.
Условни (CASE) изрази.
Користење на CASE изрази за
создавање на вкрстени упити.

Лабораториска вежба 6
Содржина
За извлекување и обработка на податоци од повеќе од една табела се извршува
обединување на табели, тоа обединување се изразува во комбинирање на колоните на
примарните и надворешните клучеви (на соодветните табели) на соодветните редови. Во
SQL синтакса ANSI - стандардот JOIN има пет типа на операции:

• INNER JOIN
• LEFT JOIN
• RIGHT JOIN
• FULL JOIN
• CROSS JOIN
• Задача

• Условни (CASE) изрази


▫ CASE
▫ NULLIF
▫ COALESCE
▫ ISNULL

• Користење на CASE изрази за создавање на крстосани упити


• Задачи
INNER JOIN

TableA INNER JOIN TableB ON join_condition

• Внатрешнo соединување, реализирано со операторот INNER


JOIN, враќа редови од која и да е табела само ако има соодветен
ред од другата табела, т.е. извлекуват се сите редови, за кои е
исполнет услов за соединување наведен во ON.

Пример:
1) Упит со кој се извлекуваат имињата на вработените, дати на
продажби, сума од општата вредност на продажбите,
реализирани од соодветниот служител на соодветната дата.

SELECT FirstName, LastName, SaleDate, TotalForSale


FROM Employees
INNER JOIN Sales ON Employees.EmployeeID = Sales.EmployeeID
2) Упит кој ги извлекува имињата на вработените, датум на продажба, сума од вкупната
вредност на продажбите, реализирани од одреден вработен на соодветна дата.

SELECT e.FirstName, e.LastName,


       CONVERT(datetime,CONVERT(char(10),s.SaleDate,102))
            AS DateOfSale,
       SUM(TotalForSale) AS Total
FROM Employees AS e
INNER JOIN Sales AS s ON e.EmployeeID = s.EmployeeID
GROUP BY e.FirstName, e.LastName,
       CONVERT(datetime,CONVERT(char(10),s.SaleDate,102))

Во овој пример е покажан начин за задавање на псевдоним на табелата после FROM,


при што се користи клучовиот збор AS. Синтаксата за задавање на псевдоним на
табела е:

FROM table_name [AS] alias_name
INNER JOIN other_table_name [AS] other_alias_name
ON join_condition

3) Упит, ги извлекува имињата на клиентите, датите на
извршените пазарувања извршени од соодветен клиент,
имињата на продуктите, продажните цени и
продаденото количество на продуктите при соодветната
продажба.

SELECT c.CompanyName, s.SaleDate, p.ProductName,


       sd.Price, sd.Quantity
FROM Customers AS c
INNER JOIN Sales s ON c.CustomerID = s.CustomerID
INNER JOIN SaleDetails sd ON s.SaleID = sd.SaleID
INNER JOIN Products p ON sd.ProductID = p.ProductID
LEFT [OUTER] JOIN

TableA LEFT [OUTER] JOIN TableB ON join_condition

• Лево внатрешно соединување, реализирано со операторот LEFT OUTER JOIN,


враќа редови, за кои постои врзка меѓу TableA и TableB, освен тоа ги враќа сите
редови од TableA, за кои нема соодветен ред од TableB, т.е. овој вид на соединување
ги зачувува несоодветните редови од TableA. При враќањето на несоодветни редови
од TableA, сите колони избрани од TableB, се враќат како NULL.
Пример:
4) Упит, со кој се извлекуваат имињата на клиентите, точната дата и час на
извршеното пазарување, имињата на купените продукти, продажната цена и
продаденото количество; а за клиенти, кој не се пазарувале, им се изведува името, а
сите останати колони се NULL.

SELECT c.CompanyName, s.SaleDate, p.ProductName,


       sd.Price, sd.Quantity
FROM Customers AS c
LEFT OUTER JOIN Sales s ON c.CustomerID = s.CustomerID
LEFT OUTER JOIN SaleDetails sd ON s.SaleID = sd.SaleID
LEFT OUTER JOIN Products p ON sd.ProductID = p.ProductID
5) Упит, со кој се извлекуваат имињата на продуктите,
точната дата и час на извршеното пазарување,
продажната цена и продаденото количество; за
продукти, които не са купувани, се извлекуваат
имињата, а за сите останати колони се враќат како
NULL.

SELECT p.ProductName, s.SaleDate, sd.Price, sd.Quantity


FROM Products AS p
LEFT JOIN SaleDetails sd ON sd.ProductID = p.ProductID
LEFT JOIN Sales s ON sd.SaleID = s.SaleID
RIGHT [OUTER] JOIN
TableA RIGHT [OUTER] JOIN TableB ON join_condition

• Десно внатрешно соединување, реализирано со операторот RIGHT OUTER


JOIN, враќа редови за кој постои врзка меѓу TableA и TableB, освен тоа ги
враќа сите редови од TableB, за кои нема соодветен ред од TableA, т.е. овој вид
на соединување ги зачувува несоодветните редови од TableB. При враќањето
на несоодветни редови од TableB, сите колони избрани од TableA, се враќат
како NULL.
Пример:
6) Упитот од пример 4 може да се запише со десно внатрешно соединувањена
следниот начин:
SELECT c.CompanyName, s.SaleDate, p.ProductName,
       sd.Price, sd.Quantity
FROM Sales AS s
INNER JOIN SaleDetails sd ON s.SaleID = sd.SaleID
INNER JOIN Products p ON sd.ProductID = p.ProductID
RIGHT OUTER JOIN Customers c
   ON s.CustomerID = c.CustomerID
7) Упитот од пример 5 може да се запише со десно
внатрешно соединување на следниот начин:

SELECT p.ProductName, s.SaleDate, sd.Price, sd.Quantity


FROM Sales s
INNER JOIN SaleDetails sd ON s.SaleID = sd.SaleID
RIGHT JOIN Products p ON sd.ProductID = p.ProductID
FULL [OUTER] JOIN
TableA FULL [OUTER] JOIN TableB ON join_condition
• Полно внатрешно соединување, реализирано со операторот FULL OUTER
JOIN, враќа редови за кој постои врзка меѓу TableA и TableB. освен тоа ги враќа
сите редови од TableA, за кој нема соодветен ред од TableB, ги враќа исто така
сите редови од TableB, за кои нема соодветен ред од TableA, т.е. овој вид на
соединување ги зачувува несоодветните редови од TableA и TableB. При
враќање на несоодветните редови од TableA, сите колони избрани од TableB, се
враќат како NULL, а враќање на несоодветните редови од TableB, сите колони
од TableA, се враќат како NULL.
Пример:
8) Упитот , со кој се извлекуваат имињата на сите клиенти, вклучително и на
оние кој не се пазарувале, имињата на сите продукти вклучително и на тие кој
не се купувани.
SELECT c.CompanyName, s.SaleDate, p.ProductName,
       sd.Price, sd.Quantity
FROM Customers AS c
FULL OUTER JOIN Sales s ON c.CustomerID = s.CustomerID
FULL OUTER JOIN SaleDetails sd ON s.SaleID = sd.SaleID
CROSS JOIN

TableA CROSS JOIN TableB

• Вкрстено соединување, реализирано со операторот


CROSS JOIN, ги враќа сите редови од TableA,
комбинирани со сите редови од TableB. При овој вид на
соединување не се користи ON, т.е. не се задава услов за
соединување преку сврзаните колони на табелите, при
што следува дека CROSS JOIN враќа декартов производ
на двете табели.
Пример:

SELECT e.City AS Employees_City, c.City AS Customer_City


FROM Employees e CROSS JOIN Customers c
Задача 1. Да се напише упит, кој изведува
идентификатор и презиме на служител, презиме на
менаџер на соодветниот служител.
Решение:
SELECT e.EmployeeID, e.LastName, e1.LastName AS
Manager
FROM Employees AS e
INNER JOIN Employees AS e1
   ON e1.EmployeeID = e.ManagerEmpID

Ако колоната ManagerEmpID допушта вредност NULL, за


да се изведат и служителите, кој немат менаџер, се
користи внатрешно соединување на следниот начин:

SELECT e.EmployeeID, e.LastName, e1.LastName AS


Manager
FROM Employees AS e
LEFT JOIN Employees AS e1
  ON e1.EmployeeID = e.ManagerEmpID
CASE

• Условниот израз може да врати една од неколку вредности


во зависност од тоа кој услов е исполнет. Се користат две
форми на функцијата CASE.

I. Синтакса во првиот случај е:


CASE value_expression
   { WHEN value_expression
          THEN {value_expression | NULL} }…
     [ELSE {value_expression | NULL}]
END

Условите се проверуваат по ред, првиот услов кој ќе се


исполни ни го определува резултатот. Ако ELSE се
пропушти, се зема ELSE NULL.
Пример:

SELECT ProductName,
        CASE discontinued
        WHEN 0 THEN 'Continued'
           WHEN 1 THEN 'Discontinued'
        ELSE 'Unknown'
        END AS DiscontinuedProducts
FROM Products
II. Синтакса при вториот случај е:
CASE
  {WHEN boolean_expression
   THEN {value_expression | NULL}}…
  [ELSE {value_expression | NULL}]
END

Пример:
SELECT SaleID, ProductID, Quantity, Price,
       CASE
           WHEN Quantity >= 20 THEN 0.05
           WHEN Quantity >= 15 THEN 0.03
            WHEN Quantity >= 10 THEN 0.02
            ELSE 0
       END AS ComputedDiscount
FROM SaleDetails
• CASE изразот во SQL Server се состои од три функции:
NULLIF и COALESCE, кои се дел од ANSI SQL92 -
стандардот; ISNULL е дополнителна функција во SQL Server и
не е дел од ANSI SQL92 - стандардот.

NULLIF, COALESCE, ISNULL

• NULLIF прифаќа две вредности за аргументи. Ако двете


вредности се совпаѓаат, резултатот е NULL; во спротивно,
резултатот е првата од двете вредности, т.е. NULLIF
(value_expression1, value_expression2) може да се запише
преку еквивалентен CASE израз на следниов начин:

CASE value_expression1
  WHEN value_expression2 THEN NULL
  ELSE value_expression1
END
• COALESCE го враќа првиот израз, кој не е NULL на списокот со изрази. Ако
сите вредности се NULL, COALESCE враќа NULL. COALESCE
(value_expression1, ..., value_expressionN) може да се запише преку
еквивалентен CASE израз на следниов начин:
CASE
    WHEN value_expression1 IS NOT NULL
         THEN value_expression1
    WHEN value_expression2 IS NOT NULL
         THEN value_expression2
    …
    ELSE value_expressionN
END
Пример: за прикажување на следната вредност во колоната идентификатор на
производ преку изнаоѓање на највисоката тековна вредност во колоната
идентификатор на производ (ProductID) од табелата за производите (Products)
и додавање на единица (може да се користи во конструкција пресметка на
следната вредност на колоната ProductID):

SELECT COALESCE(MAX(ProductID), 0) + 1 AS NextProductID


FROM Products
• ISNULL прифаќа две вредности за аргументи и ја враќа првата, ако не е NULL, а
ја втората во спротивно. ISNULL (value_expression1, value_expression2) може да
се запише преку еквивалентен CASE израз на следниов начин:
CASE
    WHEN value_expression1 IS NOT NULL
         THEN value_expression1
    ELSE value_expression2
END
Пример: 1) Упитот, ги изведува имињата и цените на производите. Ако производот
има вредност NULL за колоната price, се враќа 0.
SELECT ProductName, ISNULL (price, 0) AS ProductPrice
FROM Products
2) Упит, кој ги изведува имињата и цените на производите. Ако производот има
вредност NULL за колоната price, се враќа најниската цена која постои за некој
производ.
SELECT ProductName,
       ISNULL(price, (SELECT MIN(price) FROM Products))
         AS ProductPrice
FROM Products
Задача 1. Да се напише упит, кој враќа податоци за
продажби и пресметува попуст во зависност од
вредноста на TotalForSale: за заедничка сума на
продажбата повеќе од 100 - 15%; помеѓу 80 и 100 -
10%; помеѓу 50 и 80 - 5%; под 50 - 0%.

Задача 2. Да се напише упит, кој ги враќа имињата


и испорачана цени на производите класифицирани
како евтини, средно скапи и скапи.
Користење на CASE изрази за создавање на
крстосани упити

• CASE изразите можат да се користат за создавање на


така наречените крстосани упити (crosstab report), кој
се разликуваат по тоа што конкретните вредноси на
колоните се користат за заглавија на колоните. Се
користат за табеларно преставување на зависности на
вредности во колоните и редовите.

• Задача 1. Да се напише упит, кој изведува продадени


количини на продукти за сите тримесечија за минатата
година во видот:
ProductID ProductName I II III IV Total
1 SomeName 150000 100000 180000 187000 617000
...
Решение:
SELECT p.ProductID, p.ProductName,
       SUM(CASE DATEPART(quarter, SaleDate)
                WHEN 1 THEN quantity
                ELSE 0
           END) AS [I quarter],
       SUM(CASE DATEPART(quarter, SaleDate)
                WHEN 2 THEN quantity
                ELSE 0
           END) AS [II quarter],
       SUM(CASE DATEPART(quarter, SaleDate)
                WHEN 3 THEN quantity
                ELSE 0
           END) AS [III quarter],
       SUM(CASE DATEPART(quarter, SaleDate)
                WHEN 4 THEN quantity
                ELSE 0
           END) AS [IV quarter],
       SUM(quantity) AS Total
FROM Products p
INNER JOIN SaleDetails sd ON p.ProductID = sd.ProductID
INNER JOIN Sales s ON sd.SaleID = s.SaleID
WHERE DATEDIFF(year, SaleDate, GETDATE()) = 1
GROUP BY p.ProductID, p.ProductName
Задача 2. Да се напише упит, кој изведува вкупната
сума од продажбите за последните три месеца по
продавница во вида:
Последните Продавница А Продавница B Продавница C Вкупно
три месеца
Јануари 6000 5000 3000 14000

Февруари 5500 6500 3210 15210

Март 6800 3214 5432 15446

Решение:

SELECT DATENAME(month, s.SaleDate)


            AS [Последните три месеца],
SUM(CASE StoreName
                WHEN 'Продавница А'
                      THEN s.TotalForSale*(1-s.discount)
                ELSE 0
           END) AS [Продавница А],
       SUM(CASE StoreName
                WHEN 'Продавница B'
                      THEN s.TotalForSale*(1-s.discount)
                ELSE 0
           END) AS [Продавница B],
       SUM(CASE StoreName
                WHEN ' Продавница C'
                      THEN s.TotalForSale*(1-s.discount)
                ELSE 0
           END) AS [Продавница C],
       SUM(s.TotalForSale*(1-s.discount)) AS [Вкупно]
FROM Stores st
INNER JOIN Employees e ON st.StoreID = e.StoreID
INNER JOIN Sales s ON e.EmployeeID = s.EmployeeID
WHERE DATEDIFF(month, SaleDate, GetDATE())
      BETWEEN 1 AND 3
GROUP BY DATEPART(month, s.SaleDate),
         DATENAME(month, s.SaleDate)
ORDER BY DATEPART(month, s.SaleDate) ASC
За упитот од задача 2 се неопходни CASE изрази од видот:

CASE StoreName
     WHEN 'Some store name'
     THEN s.TotalForSale*(1-s.discount)
     ELSE 0
END

За секој израз се користи вредност на колоната StoreName во табелата


Stores. Следниот упит враќа како резултат CASE изразите, неопходни за
составуање на крстосани упити од задача 2.

SELECT 'SUM(CASE StoreName


               WHEN ''' + StoreName + '''
               THEN s.TotalForSale*(1-s.Discount)
               ELSE 0
            END) AS [' + StoreName + '],'
FROM Stores

You might also like