SQL Server Szybki trening 2

Cezary Walenciuk

SQL Server Szybki Trening 2

@walenciukC

Speaker
6. Zaawansowana Zapytania SELECT

6-0 Pobierz mi pierwsze 10 rekordów unikatowych

                    
                        SELECT DISTINCT TOP (10) HireDate
                        FROM HumanResources.Employee
                        ORDER BY HireDate;
                    
                

blog
Copyright © Cezary Walenciuk

6-0 Filtrowanie rezultatu z podzapytania

                    
                        SELECT s.PurchaseOrderNumber
                        FROM Sales.SalesOrderHeader s
                        WHERE EXISTS ( SELECT SalesOrderID
                        FROM Sales.SalesOrderDetail
                        WHERE UnitPrice BETWEEN 1900 AND 2000
                        AND SalesOrderID = s.SalesOrderID )
                        ORDER BY s.PurchaseOrderNumber;
                    
                

blog
Copyright © Cezary Walenciuk

6-0-2 Filtrowanie rezultatu z podzapytania

                    
                        SELECT DISTINCT sh.PurchaseOrderNumber
                        FROM Sales.SalesOrderHeader AS sh
                        JOIN Sales.SalesOrderDetail AS sd
                        ON sh.SalesOrderID = sd.SalesOrderID
                        WHERE sd.UnitPrice BETWEEN 1900 AND 2000;
                    
                

blog
Copyright © Cezary Walenciuk

6-0-3 Zwrócenie losowych wierszy z tabeli

                    
                        SELECT FirstName,
                        LastName
                        FROM Person.Person
                        TABLESAMPLE SYSTEM (2 PERCENT);
                    
                

blog
Copyright © Cezary Walenciuk
6-0
Zapytania z gotowymi wynikami

6-0 Zapytania z gotowymi wynikami

                    
                        SELECT *
                        FROM (VALUES ('Adam', 'Walkuz'),
                        ('Stefan', 'Jefferson'))
                         dtPeople(FirstName, LastName);
                    
                

6-1
Wyświetlenie danych ze zmiennych

6-1 Wyświetlenie danych ze zmiennych

                    
                        DECLARE @FirstHireDate DATE,
                        @LastHireDate DATE;

                        SELECT @FirstHireDate = MIN(HireDate),
                        @LastHireDate = MAX(HireDate)
                        FROM HumanResources.Employee;

                        SELECT @FirstHireDate AS FirstHireDate,
                        @LastHireDate AS LastHireDate;
                    
                

blog
Copyright © Cezary Walenciuk
6-2
Tworzenie nowej tabeli z wyniku zapytania

6-2 Tworzenie nowej tabeli z wyniku zapytania

                    
                        IF OBJECT_ID('dbo.mySales') 
                        IS NOT NULL DROP TABLE dbo.mySales;

                        SELECT *
                        INTO dbo.mySales
                        FROM Sales.SalesOrderDetail
                        WHERE ModifiedDate = '2011-06-01T00:00:00.000';

                        SELECT COUNT(*) AS QtyOfRows
                        FROM dbo.mySales;
                    
                

Limity

Limity

6-3
Wysłanie rekordów do funkcji

6-3 Wysłanie rekordów do funkcji

                    
                        IF OBJECT_ID('dbo.fn_WorkOrderRouting') IS NOT NULL DROP FUNCTION dbo.fn_WorkOrderRouting;
                        GO
                        CREATE FUNCTION dbo.fn_WorkOrderRouting (@WorkOrderID INT)
                            RETURNS TABLE
                            AS
                            RETURN
                                SELECT WorkOrderID,
                                ProductID,
                                OperationSequence,
                                LocationID
                                FROM Production.WorkOrderRouting
                                WHERE WorkOrderID = @WorkOrderID;
                        GO

                        SELECT TOP (5)
                        w.WorkOrderID,
                        w.OrderQty,
                        r.ProductID,
                        r.OperationSequence
                        FROM Production.WorkOrder w
                            CROSS APPLY dbo.fn_WorkOrderRouting(w.WorkOrderID) AS r
                        ORDER BY w.WorkOrderID,
                        w.OrderQty,
                        r.ProductID;
                    
                

6-3-2 Wysłanie rekordów do funkcji

                    
                        SELECT TOP (5)
                        w.WorkOrderID,
                        w.OrderQty,
                        r.ProductID,
                        r.OperationSequence
                        FROM Production.WorkOrder w
                        CROSS APPLY (
                            SELECT WorkOrderID,
                            ProductID,
                            OperationSequence,
                            LocationID
                            FROM Production.WorkOrderRouting
                            WHERE WorkOrderID = w.WorkOrderId
                        ) AS r
                        ORDER BY w.WorkOrderID,
                        w.OrderQty,
                        r.ProductID;
                    
                

6-4
Zmiana wierszy na kolumny
blog
Copyright © Cezary Walenciuk

6-4 Zmiana wierszy na kolumny

                    

                        SELECT s.Name AS ShiftName,
                        h.BusinessEntityID,
                        d.Name AS DepartmentName
                        FROM HumanResources.EmployeeDepartmentHistory h
                        INNER JOIN HumanResources.Department d
                        ON h.DepartmentID = d.DepartmentID
                        INNER JOIN HumanResources.Shift s
                        ON h.ShiftID = s.ShiftID
                        WHERE EndDate IS NULL
                        AND d.Name IN ('Production', 'Engineering', 'Marketing')
                        ORDER BY ShiftName;
                    
                

blog
Copyright © Cezary Walenciuk

6-4-2 Zmiana wierszy na kolumny

                    

                        SELECT ShiftName,
                        Production,
                        Engineering,
                        Marketing
                        FROM 
                        
                        (   SELECT s.Name AS ShiftName,
                            h.BusinessEntityID,
                            d.Name AS DepartmentName
                            FROM HumanResources.EmployeeDepartmentHistory h
                            INNER JOIN HumanResources.Department d
                            ON h.DepartmentID = d.DepartmentID
                            INNER JOIN HumanResources.Shift s
                            ON h.ShiftID = s.ShiftID
                            WHERE EndDate IS NULL
                            AND d.Name IN ('Production', 'Engineering', 'Marketing')
                        ) 
                        
                        AS a
                        PIVOT
                        (
                            COUNT(BusinessEntityID)
                            FOR DepartmentName IN ([Production], [Engineering], [Marketing])
                        ) AS b
                    
                

blog
Copyright © Cezary Walenciuk

6-4-3 Zmiana wierszy na kolumny

                    
                        FROM table_source
                        PIVOT ( aggregate_function ( value_column )
                        FOR pivot_column
                        IN ( <column_list>)
                        ) table_alias
                    
                

Argumenty PIVOT

Argumenty PIVOT

6-4-4 Zmiana wierszy na kolumny

                    
                        SELECT s.Name AS ShiftName,
                            SUM(CASE WHEN d.Name = 'Production' THEN 1 ELSE 0 END) AS Production,
                            SUM(CASE WHEN d.Name = 'Engineering' THEN 1 ELSE 0 END) AS Engineering,
                            SUM(CASE WHEN d.Name = 'Marketing' THEN 1 ELSE 0 END) AS Marketing
                        FROM HumanResources.EmployeeDepartmentHistory h
                        INNER JOIN HumanResources.Department d
                        ON h.DepartmentID = d.DepartmentID
                        INNER JOIN HumanResources.Shift s
                        ON h.ShiftID = s.ShiftID
                        WHERE h.EndDate IS NULL
                        AND d.Name IN ('Production', 'Engineering', 'Marketing')
                        GROUP BY s.Name;
                    
                

blog
Copyright © Cezary Walenciuk
6-5
Zmiana wierszy na kolumny

6-5 Zmiana kolumn na wiersze

                    
                        IF OBJECT_ID('tempdb.dbo.#Contact') IS NOT NULL DROP TABLE #Contact;
                        CREATE TABLE #Contact
                        (
                            EmployeeID INT NOT NULL,
                            PhoneNumber1 BIGINT,
                            PhoneNumber2 BIGINT,
                            PhoneNumber3 BIGINT
                        )
                        GO

                        INSERT #Contact
                        (EmployeeID, PhoneNumber1, PhoneNumber2, PhoneNumber3)
                        VALUES (1, 2718353881, 3385531980, 5324571342),
                        (2, 6007163571, 6875099415, 7756620787),
                        (3, 9439250939, NULL, NULL);
                    
                

6-5-2 Zmiana kolumn na wiersze

                    
                        SELECT EmployeeID,
                            [PhoneNumber1],
                            [PhoneNumber2],
							[PhoneNumber3]
                        FROM #Contact c
                    
                

blog
Copyright © Cezary Walenciuk

6-5-3 Zmiana kolumn na wiersze

                    
                        SELECT EmployeeID,
                            PhoneType,
                            PhoneValue
                            FROM #Contact c
                        UNPIVOT
                        (
                            PhoneValue
                            FOR PhoneType IN ([PhoneNumber1], [PhoneNumber2], 
                            [PhoneNumber3])
                        ) AS p;
                    
                

blog
Copyright © Cezary Walenciuk

6-5-4 Zmiana kolumn na wiersze

                    
                        SELECT EmployeeID,
                        'PhoneNumber1' AS PhoneType,
                        c.PhoneNumber1 AS PhoneValue
                        FROM #Contact c
                        WHERE c.PhoneNumber1 IS NOT NULL
                        UNION ALL
                        SELECT EmployeeID,
                        'PhoneNumber2' AS PhoneType,
                        c.PhoneNumber2 AS PhoneValue
                        FROM #Contact c
                        WHERE c.PhoneNumber2 IS NOT NULL
                        UNION ALL
                        SELECT EmployeeID,
                        'PhoneNumber3' AS PhoneType,
                        c.PhoneNumber3 AS PhoneValue
                        FROM #Contact c
                        WHERE c.PhoneNumber3 IS NOT NULL
                        ORDER BY EmployeeID, PhoneType;
                    
                

6-6
Używanie zapytań ponownie

6-6 Używanie zapytań ponownie

                    
                        WITH cte AS
                        (
                            SELECT SalesOrderID
                            FROM Sales.SalesOrderDetail
                            WHERE UnitPrice BETWEEN 1900 AND 2000
                        )

                        SELECT s.PurchaseOrderNumber
                        FROM Sales.SalesOrderHeader s
                        WHERE EXISTS (SELECT SalesOrderID
                        FROM cte
                        WHERE SalesOrderID = s.SalesOrderID );
                    
                

blog
Copyright © Cezary Walenciuk

6-7-1 Używanie zapytań ponownie

                    
                        WITH expression_name
                        [ ( column_name [ ,...n ] ) ] 
                        AS ( CTE_query_SELECT_definition )
                    
                

Argumenty CTE

6-7-2 Używanie zapytań ponownie

                    
                        WITH CTE(N, D) AS
                        (
                            SELECT TOP (5) object_id, type_desc
                            FROM sys.objects
                        )
                        SELECT N,D FROM CTE;
                    
                

Mamy dwa typy Common Table Expression

CTE

6-7-2 Używanie zapytań ponownie

                    
                        WITH VendorSearch(RowNumber, VendorName, AccountNumber) AS
                        (
                            SELECT ROW_NUMBER() OVER (ORDER BY Name) RowNum,
                            Name,
                            AccountNumber
                            FROM Purchasing.Vendor
                        )

                        SELECT * FROM VendorSearch;
						SELECT * FROM VendorSearch;
                    
                

blog
Copyright © Cezary Walenciuk
6-8
Zapytania na tabelkach rekurecyjnych

6-8-1 Zapytania na tabelkach rekurecyjnych

                    
                        IF OBJECT_ID('tempdb.dbo.#Company') IS NOT NULL DROP TABLE #Company;
                        CREATE TABLE #Company
                        (
                            CompanyID INT NOT NULL
                            PRIMARY KEY,
                            ParentCompany ID INT NULL,
                            CompanyName VARCHAR(25) NOT NULL
                        );

                        INSERT #Company
                        (CompanyID, ParentCompanyID, CompanyName)
                        VALUES (1, NULL, 'A-Corp'),
                        (2, 1, 'B-Corp'),
                        (3, 1, 'C-Corp'),
                        (4, 3, 'D-Corp'),
                        (5, 4, 'F-Corp'),
                        (6, 5, 'E-Corp'),
                        (7, 5, 'G-Corp');
                    
                

blog
Copyright © Cezary Walenciuk

6-8-2 Zapytania na tabelkach rekurecyjnych

                    
                        WITH CompanyTree(ParentCompanyID, CompanyID, CompanyName, CompanyLevel) AS
                        (
                            -- Anchor Member
                            SELECT ParentCompanyID,
                            CompanyID,
                            CompanyName,
                            0 AS CompanyLevel
                            FROM #Company
                            WHERE ParentCompanyID IS NULL
                            UNION ALL
                            -- Recursive Member
                            SELECT c.ParentCompanyID,
                            c.CompanyID,
                            c.CompanyName,
                            p.CompanyLevel + 1
                            FROM #Company c
                            INNER JOIN CompanyTree p
                            ON c.ParentCompanyID = p.CompanyID
                        )

                        SELECT ParentCompanyID,
                        CompanyID,
                        CompanyName,
                        CompanyLevel
                        FROM CompanyTree;
                        option (maxrecursion 5)
                    
                

Głębia

6-6-3 Zapytania na tabelkach rekurecyjnych

                    
                        SELECT ParentCompanyID,
                        CompanyID,
                        CompanyName,
                        CompanyLevel
                        FROM CompanyTree
                        option (MaxRecursion  2)
                    
                

7. Window function i słowo kluczowe OVER
blog
Copyright © Cezary Walenciuk
Window Function pozwala twojemu zapytaniu SQL spojrzeć na podzbiór wierszy, które są zwracane przez zapytanie zanim funkcja agregująca zadziała na te wiersze

5-2 Grupowanie podstawy z groupby

                    
                        SELECT AVG(Grade) AS AvgGrade,
                        AVG(DISTINCT Grade) AS AvgDistinctGrade,
                        MAX(Grade) AS MaxGrade,
                        MIN(Grade) AS MinGrade
                        FROM (VALUES (1, 100),
                        (1, 99),
                        (1, 99),
                        (1, 98),
                        (1, 99),
                        (1, 32),
                        (2, 77),
                        (2, 56),
                        (2, 88),
                        (2, 60),
                        (2, 80)
                        ) dt (StudentId, Grade)
            
                        GROUP BY StudentId
                    
                

blog
Copyright © Cezary Walenciuk

7-0-0 Grupowanie podstawy z groupby

                    
                        SELECT 
                        StudentId,Grade
                        FROM (VALUES (1, 100),
                       (1, 99),
                       (1, 99),
                       (1, 98),
                       (1, 99),
                       (1, 32),
                       (2, 77),
                       (2, 56),
                       (2, 88),
                       (2, 60),
                       (2, 80)
                       ) dt (StudentId, Grade)
                                   
                       GROUP BY StudentId
                    
                

blog
Copyright © Cezary Walenciuk

7-0-0 Grupowanie podstawy z groupby

                    
                        SELECT 
                        StudentId,
                        AVG(Grade) OVER (ORDER BY StudentId) 
                        FROM (VALUES (1, 100),
                        (1, 99),
                        (1, 99),
                        (1, 98),
                        (1, 99),
                        (1, 32),
                        (2, 77),
                        (2, 22),
                        (2, 88),
                        (2, 60),
                        (2, 80)
                        ) dt (StudentId, Grade)
                    
                

blog
Copyright © Cezary Walenciuk

7-0-0 Grupowanie podstawy z groupby

                    
                        SELECT 
                        Distinct StudentId,
                        AVG(Grade) OVER (ORDER BY StudentId) 
                        FROM (VALUES (1, 100),
                        (1, 99),
                        (1, 99),
                        (1, 98),
                        (1, 99),
                        (1, 32),
                        (2, 77),
                        (2, 22),
                        (2, 88),
                        (2, 60),
                        (2, 80)
                        ) dt (StudentId, Grade)
                    
                

blog
Copyright © Cezary Walenciuk
Dodajmy więcej studentów bo nic z tego okna nie widać

7-0-0 Grupowanie podstawy z groupby

                    
                        SELECT 
                        StudentId,
                        AVG(Grade) OVER (ORDER BY StudentId) 
                        FROM (VALUES (11, 100),
                        (1, 99),
                        (2, 99),
                        (3, 98),
                        (4, 99),
                        (5, 32),
                        (6, 77),
                        (7, 22),
                        (8, 88),
                        (9, 60),
                        (10, 80)
                        ) dt (StudentId, Grade)
                    
                

blog
Copyright © Cezary Walenciuk
Window Function pozwala twojemu zapytaniu SQL spojrzeć na podzbiór wierszy, które są zwracane przez zapytanie zanim funkcja agregująca zadziała na te wiersze
W ten sposób funkcje pozwalają tobie określeć odpowiednią kolejność danych, które mają trafić do pewnej operacji

7-0 PRZYKŁAD

                    
                        SELECT duration_seconds,
                        SUM(duration_seconds) OVER 
                        (ORDER BY id) 
                        AS running_total
                        FROM [demo].[dbo].[Runinng]
                    
                

blog
Copyright © Cezary Walenciuk

7-0 PRZYKŁAD

                    
                        SELECT duration_seconds,
                        SUM(duration_seconds) OVER 
                        (ORDER BY  id DESC)
                        AS running_total
                        FROM [demo].[dbo].[Runinng]
                    
                

blog
Copyright © Cezary Walenciuk
Lepsze to niż : self-join czy iterację po pętli
Window Function pozwala tobie kontrolować kolejność danych które mają trafić do funkcji agregującej

Jakie funkcje agregujące mogą być wykonane ze słowem OVER

Są jeszcze funkcje rankingowe

Funkcje rankingowe

7-0-0 Grupowanie podstawy z groupby

                    
                        SELECT 
                        StudentId,
                        RANK()  OVER (ORDER BY Grade) AS RANK,
                        DENSE_RANK() OVER (ORDER BY Grade) AS DENSE_RANK,
                        ROW_NUMBER() OVER (ORDER BY Grade) AS ROW_NUMBER,
                        AVG(Grade) OVER (ORDER BY Grade) AS AVGGrade
                        FROM (VALUES (11, 100),
                        (1, 99),
                        (2, 99),
                        (3, 98),
                        (4, 99),
                        (5, 32),
                        (6, 77),
                        (7, 22),
                        (8, 88),
                        (9, 60),
                        (10, 80)
                        ) dt (StudentId, Grade)
                    
                

blog
Copyright © Cezary Walenciuk
blog
Copyright © Cezary Walenciuk

Funkcje analityczne, a Offset functions

5-2 Grupowanie podstawy z groupby

                    
                        SELECT 
                        StudentId,
                        LAG(Grade,1)  OVER (ORDER BY Grade) AS PreviousGrade,
                        LEAD(Grade,1) OVER (ORDER BY Grade) AS NextGrade,
                        FIRST_VALUE(Grade) OVER (ORDER BY Grade) AS FirstGrade,
                        LAST_VALUE(Grade)  OVER (ORDER BY Grade) AS LastGrade
                        FROM (VALUES (11, 100),
                        (1, 99),
                        (2, 99),
                        (3, 98),
                        (4, 99),
                        (5, 32),
                        (6, 77),
                        (7, 22),
                        (8, 88),
                        (9, 60),
                        (10, 80)
                        ) dt (StudentId, Grade)
                    
                

blog
Copyright © Cezary Walenciuk
7-1
Kalkulacje na podstawie kolejności wierszy

7-1 Kalkulacje na podstawie kolejności wierszy

                    

                        CREATE TABLE #Transactions
                        (
                            AccountId INTEGER,
                            TranDate DATE,
                            TranAmt NUMERIC(8, 2)
                        );
                        INSERT INTO #Transactions
                        SELECT *
                        FROM ( VALUES 
                        ( 1, '2011-01-01', 500),
                        ( 1, '2011-01-15', 50),
                        ( 1, '2011-01-22', 250),
                        ( 1, '2011-01-24', 75),
                        ( 1, '2011-01-26', 125),
                        ( 1, '2011-01-26', 175),
                        ( 2, '2011-01-01', 500),
                        ( 2, '2011-01-15', 50),
                        ( 2, '2011-01-22', 25),
                        ( 3, '2011-01-22', 5000),
                        ( 3, '2011-01-27', 550),
                        ( 3, '2011-01-27', 95 ),
                        ( 3, '2011-01-30', 2500)
                        ) dt (AccountId, TranDate, TranAmt);
                    
                

7-1-1 Kalkulacje na podstawie kolejności wierszy

                    
                        SELECT AccountId,
                        TranDate,
                        TranAmt,
                        -- Suma dla wszystkich transakcji według daty 
                        -- i podzielona/resetowana przez AccountId
                        RunTotalAmt = SUM(TranAmt) 
                        OVER (PARTITION BY AccountId ORDER BY TranDate)
                        FROM #Transactions AS t
                        ORDER BY AccountId,
                        TranDate;
                    
                

blog
Copyright © Cezary Walenciuk
blog
Copyright © Cezary Walenciuk

7-1-2 Kalkulacje na podstawie kolejności wierszy

                    
                        SELECT AccountId,
                        TranDate,
                        TranAmt,
                        -- Suma dla wszystkich transakcji według daty
                        RunTotalAmt = SUM(TranAmt) 
                        OVER (ORDER BY TranDate)
                        FROM #Transactions AS t
                        ORDER BY 
                        RunTotalAmt;
                    
                

blog
Copyright © Cezary Walenciuk

7-1-3 Kalkulacje na podstawie kolejności wierszy

                    
                        SELECT AccountId,
                        TranDate,
                        TranAmt,
                        -- Suma dla wszystkich transakcji według daty
                        RunTotalAmt = SUM(TranAmt) OVER (PARTITION BY AccountId ORDER BY TranDate),
                        -- Suma dla wszystkich transakcji według daty 
                        -- (jeżeli są dwie takie same daty to nie łączymy)
                        RunTotalAmt2 = SUM(TranAmt) OVER (PARTITION BY AccountId
                        ORDER BY TranDate
                        ROWS UNBOUNDED PRECEDING)
                        FROM #Transactions AS t
                        ORDER BY AccountId,
                        TranDate;
                    
                

7-1-4 Przykład

                    
                        OVER (
                            [ <PARTITION BY clause> ]
                            [ <ORDER BY clause> ]
                            [ <ROW or RANGE clause> ]
                        )
                    
                

blog
Copyright © Cezary Walenciuk
blog
Copyright © Cezary Walenciuk

7-1-3 Kalkulacje na podstawie kolejności wierszy

                    
                        SELECT AccountId,
                        TranDate,
                        TranAmt,
        
                        RunAvg = AVG(TranAmt) OVER (PARTITION BY AccountId ORDER BY TranDate),
                      
                        RunTranQty = COUNT(*) OVER (PARTITION BY AccountId ORDER BY TranDate),
              
                        RunSmallAmt = MIN(TranAmt) OVER (PARTITION BY AccountId ORDER BY TranDate),
            
                        RunLargeAmt = MAX(TranAmt) OVER (PARTITION BY AccountId ORDER BY TranDate),
          
                        RunTotalAmt = SUM(TranAmt) OVER (PARTITION BY AccountId ORDER BY TranDate)

                        FROM #Transactions AS t
                        WHERE AccountID = 1
                        ORDER BY AccountId, TranDate;
                    
                

blog
Copyright © Cezary Walenciuk
7-2
Kalkulacje na obecnym wierszu i dwówch poprzednich

7-2-0 Przykład

                    
                        OVER (
                            [ <PARTITION BY clause> ]
                            [ <ORDER BY clause> ]
                            [ <ROW or RANGE clause> ]
                        )
                    
                

7-2 Kalkulacje na obecnym wierszu i dwówch poprzednich

                    
                        SELECT AccountId,
                        TranDate,
                        TranAmt,

                        -- Liczba # obecnych i poprzednich 2 transakcji
                        SlideQty = COUNT(*)
                        OVER (PARTITION BY AccountId
                        ORDER BY TranDate
                        ROWS BETWEEN 2 PRECEDING AND CURRENT ROW),

                        -- Suma obecna i poprzednich 2 transakcji
                        SlideTotal = SUM(TranAmt)
                        OVER (PARTITION BY AccountId
                        ORDER BY TranDate
                        ROWS BETWEEN 2 PRECEDING AND CURRENT ROW)

                        FROM #Transactions AS t
                        ORDER BY AccountId, TranDate;
                    
                

blog
Copyright © Cezary Walenciuk
blog
Copyright © Cezary Walenciuk
7-3
Kalkulacje na podstawie procentu całości

7-3 Kalkulacje na podstawie procentu całości

                    
                        SELECT AccountId,
                        TranDate,
                        TranAmt,

                        AccountTotal = SUM(TranAmt) 
                        OVER (PARTITION BY AccountId),

                        AmountPct = TranAmt / SUM(TranAmt) 
                        OVER (PARTITION BY t.AccountId)

                        FROM #Transactions AS t
                    
                

blog
Copyright © Cezary Walenciuk
7-4
Kalkulacje na X-obecny wierszy i Y-wszystkich wierszy

Ranking functions : Funkcje rankingowe

7-4 Kalkulacje na X-obecny wierszy i Y-wszystkich wierszy

                    
                        SELECT AccountId,
                        TranDate,
                        TranAmt,
                        -- KolejnyWierszPo AccountId
                        KolejnyWierszPoId = ROW_NUMBER() OVER (PARTITION BY AccountId ORDER BY AccountId, TranDate),
                        -- KolejnyWierszPo Wszystkim
                        KolejnyWierszPoWszystkich = COUNT(*) OVER (PARTITION BY AccountId),
                        -- KolejnyWierszPo IdWiersza
                        IdWiersza = ROW_NUMBER() OVER (ORDER BY AccountId, TranDate),
                        WszystkieWiersze = COUNT(*) OVER ()
                        FROM #Transactions AS t
                        ORDER BY AccountId, TranDate;;
                    
                

blog
Copyright © Cezary Walenciuk
7-6
Generowanie kolumny z liczbą wierszy

7-6 Generowanie kolumny z liczbą wierszy

                    
                        SELECT TOP 10
                        AccountNumber,
                        OrderDate,
                        TotalDue,

                        ROW_NUMBER() OVER 
                        (PARTITION BY AccountNumber ORDER BY OrderDate) 
                        AS RowNumber

                        FROM AdventureWorks2014.Sales.SalesOrderHeader
                        ORDER BY AccountNumber;
                    
                

blog
Copyright © Cezary Walenciuk
7-6
Użycie logicznego Okna

7-7 Użycie logicznego Okna

                    

                        CREATE TABLE #Test
                        (
                            RowID INT IDENTITY,
                            FName VARCHAR(20),
                            Salary SMALLINT
                        );
                        INSERT INTO #Test (FName, Salary)
                        VALUES ('Adam', 800),
                        ('Stefan', 950),
                        ('Nosal', 1250),
                        ('Kalina', 1250), --<< powtórzenie
                        ('Patrycja', 1300),
                        ('Bartek', 1500),
                        ('Tomek', 1600),
                        ('Franek', 3000),
                        ('Cezary', 3000), --<< powtórzenie
                        ('Cezaryna', 5000);
                    
                

Framing options

7-7-1 Użycie logicznego Okna

                    
                        SELECT RowID,
                        FName,
                        Salary,
                        SumByRows = SUM(Salary) 
                        OVER (ORDER BY Salary ROWS UNBOUNDED PRECEDING),
                        SumByRange = SUM(Salary) 
                        OVER (ORDER BY Salary RANGE UNBOUNDED PRECEDING)
                        FROM #Test
                        ORDER BY RowID;
                    
                

blog
Copyright © Cezary Walenciuk
7-8
Zwracanie wierszy poprzez ich range

Ranking functions : Funkcje rankingowe

Ranking functions : Funkcje rankingowe

Ranking functions : Funkcje rankingowe

7-8 Zwracanie wierszy poprzez ich range

                    
                        SELECT BusinessEntityID,
                        SalesQuota,
                        RANK() OVER (ORDER BY SalesQuota DESC) AS RankWithGaps,
                        DENSE_RANK() OVER (ORDER BY SalesQuota DESC) AS RankWithoutGaps,
                        ROW_NUMBER() OVER (ORDER BY SalesQuota DESC) AS RowNumber
                        FROM Sales.SalesPersonQuotaHistory
                        WHERE QuotaDate = '2014-03-01'
                        AND SalesQuota < 500000;
                    
                

blog
Copyright © Cezary Walenciuk
7-8
Sortowanie rekordów do podgrup : podziel sprzedaże na 4 grupy

Ranking functions : Funkcje rankingowe

Ranking functions : Funkcje rankingowe

7-8 Sortowanie rekordów do podgrup : podziel sprzedaże na 4 grupy

                    
                        SELECT BusinessEntityID,
                        QuotaDate,
                        SalesQuota,
                        NTILE(4) OVER (ORDER BY SalesQuota DESC) AS [NTILE]
                        FROM Sales.SalesPersonQuotaHistory
                        WHERE SalesQuota BETWEEN 266000.00 AND 319000.00;
                    
                

blog
Copyright © Cezary Walenciuk

7-8-1 Sortowanie rekordów do podgrup : podziel sprzedaże na 4 grupy

                    
                        SELECT AccountId,
                        TranDate,
                        TranAmt,
						NTILE(4) OVER (ORDER BY TranAmt DESC) AS [NTILE]
                        FROM #Transactions AS t
                        ORDER BY [NTILE],
                        TranDate;
                    
                

blog
Copyright © Cezary Walenciuk
7-9
Znajdowanie luk

Funkcje analityczne, a Offset functions

Analytic functions : Funkcje analityczne

7-9 Znajdowanie luk

                    
                        CREATE TABLE #Gaps (col1 INTEGER PRIMARY KEY CLUSTERED);

                        INSERT INTO #Gaps (col1)
                        VALUES (1), (2), (3),
                        (50), (51), (52), (53), (54), (55),
                        (100), (101), (102),
                        (500),
                        (950), (951), (952),
                        (954);

                        WITH cte AS
                        (
                            SELECT col1 AS CurrentRow,
                            LEAD(col1, 1, NULL) OVER (ORDER BY col1) AS NextRow
                            FROM #Gaps
                        )

                        -- Compare the value of the current row to the next row.
                        -- If > 1, then there is a gap.
                        SELECT cte.CurrentRow + 1 AS [Start of Gap],
                        cte.NextRow - 1 AS [End of Gap]
                        FROM cte
                        WHERE cte.NextRow - cte.CurrentRow > 1;
                    
                

blog
Copyright © Cezary Walenciuk
7-10
Porównanie danych z poprzedniego miesiąca

Analytic functions : Funkcje analityczne

7-10 Lag example

                    
                        WITH cte_netsales_2018 AS(
                            SELECT 
                                month, 
                                SUM(net_sales) net_sales
                            FROM 
                                sales.vw_netsales_brands
                            WHERE 
                                year = 2018
                            GROUP BY 
                                month
                        )

                        SELECT 
                            month,
                            net_sales,
                            LAG(net_sales,1) OVER (
                                ORDER BY month
                            ) previous_month_sales
                        FROM 
                            cte_netsales_2018;
                    
                

7-11
Pobieranie pierwszej i ostatniej wartośći z partycji

Analytic functions : Funkcje analityczne

7-11 Pobieranie pierwszej i ostatniej wartośći z partycji

                    
                        SELECT DISTINCT TOP (5)
                        CustomerID,
                        -- Get the date for the customer's least expensive order
                        FIRST_VALUE(OrderDate)
                        OVER (PARTITION BY CustomerID
                        ORDER BY TotalDue
                        ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) AS OrderDateLow,
                        -- Get the date for the customer's most expensive order
                        LAST_VALUE(OrderDate)
                        OVER (PARTITION BY CustomerID
                        ORDER BY TotalDue
                        ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) AS OrderDateHigh
                        FROM Sales.SalesOrderHeader
                        ORDER BY CustomerID;
                    
                

blog
Copyright © Cezary Walenciuk
8. Transakcje, Blokady i DeadLocki

Transakcje. Zasada ACID

Swoją drogą istnieje możliwość wyłączenia NIEJAWNYCH transakcji dla poleceń

8-0

                    
                        SET IMPLICIT_TRANSACTIONS ON;
                        
                        SET IMPLICIT_TRANSACTIONS OFF;
                    
                

Jawne transakcje są lepsze

Polecenia transakcyjne

Polecenia transakcyjne

Polecenia transakcyjne

8-1
Używanie jawnych transakcji

8-1 Używanie jawnych transakcji

                    
                        /* -- Przed Liczeniem */
                        SELECT BeforeCount = COUNT(*)
                        FROM HumanResources.Department;

                        /* -- Zmienna będzie przetrzymywać ostatni błąd */
                        DECLARE @Error int;
                        BEGIN TRANSACTION
                        INSERT INTO HumanResources.Department (Name, GroupName)
                        VALUES ('Accounts Payable', 'Accounting');
                        SET @Error = @@ERROR;
                        IF (@Error<> 0)
                        GOTO Error_Handler;

                        INSERT INTO HumanResources.Department (Name, GroupName)
                        VALUES ('Engineering', 'Research and Development');
                        SET @Error = @@ERROR;
                        IF (@Error <> 0)
                        GOTO Error_Handler;
                        COMMIT TRANSACTION

                        Error_Handler:
                        IF @Error <> 0
                        BEGIN
                            ROLLBACK TRANSACTION;
                        END

                        /* -- Po */
                        SELECT AfterCount = COUNT(*)
                        FROM HumanResources.Department;
                        GO
                    
                

8-2
Wyświetlanie najstarszej transakcji

8-2 Wyświetlanie najstarszej transakcji

                    

                        USE AdventureWorks2014;
                        GO
                        BEGIN TRANSACTION
                        DELETE Production.ProductProductPhoto
                        WHERE ProductID = 317;

                        DBCC OPENTRAN('AdventureWorks2014');

                        ROLLBACK TRANSACTION;
                        GO
                    
                

blog
Copyright © Cezary Walenciuk
8-3
Pytanie o transakcje w czasie sesji

8-3 Pytanie o transakcje w czasie sesji

                    
                        --stwórzmy celowo trasakcje która nie jest zamknięta

                        SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
                        GO
                        USE AdventureWorks2014;
                        GO

                        BEGIN TRAN
                        SELECT *
                        FROM HumanResources.Department
                        INSERT INTO HumanResources.Department (Name, GroupName)
                        VALUES ('Test', 'QA');
                    
                

blog
Copyright © Cezary Walenciuk

8-3-1 Pytanie o transakcje w czasie sesji

                    
                        --w innym oknie query
                        SELECT session_id, transaction_id, is_user_transaction, is_local
                        FROM sys.dm_tran_session_transactions
                        WHERE is_user_transaction = 1;
                    
                

blog
Copyright © Cezary Walenciuk

8-3-2 Pytanie o transakcje w czasie sesji

                    
                        --w innym oknie query
                        SELECT s.text
                        FROM sys.dm_exec_connections c
                        CROSS APPLY sys.dm_exec_sql_text(c.most_recent_sql_handle) s
                        WHERE c.most_recent_session_id = 51;
                        --użyj session_id zwrócone przez poprzednie zapytanie
                        GO
                    
                

blog
Copyright © Cezary Walenciuk

8-3-3 Pytanie o transakcje w czasie sesji

                    
                        --w innym oknie query
                        SELECT transaction_begin_time
                        ,tran_type = CASE transaction_type
                        WHEN 1 THEN 'Read/write transaction'
                        WHEN 2 THEN 'Read-only transaction'
                        WHEN 3 THEN 'System transaction'
                        WHEN 4 THEN 'Distributed transaction'
                        END
                        ,tran_state = CASE transaction_state
                        WHEN 0 THEN 'not been completely initialized yet'
                        WHEN 1 THEN 'initialized but has not started'
                        WHEN 2 THEN 'active'
                        WHEN 3 THEN 'ended (read-only transaction)'
                        WHEN 4 THEN 'commit initiated for distributed transaction'
                        WHEN 5 THEN 'transaction prepared and waiting resolution'
                        WHEN 6 THEN 'committed'
                        WHEN 7 THEN 'being rolled back'
                        WHEN 8 THEN 'been rolled back'
                        END
                        FROM sys.dm_tran_active_transactions
                        WHERE transaction_id = 12969598; 
                        -- zmień wartość transaction_id 
                        GO
                        
                    
                

blog
Copyright © Cezary Walenciuk

8-3-4 Pytanie o transakcje w czasie sesji

                    
                        --stwórzmy celowo trazakcje która nie jest zamknięta

                        --SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
                        --GO
                        --USE AdventureWorks2014;
                        --GO

                        --BEGIN TRAN
                        --SELECT *
                        --FROM HumanResources.Department
                        --INSERT INTO HumanResources.Department (Name, GroupName)
                        --VALUES ('Test', 'QA'); -->
                        
                        ROLLBACK TRANSACTION;
                    
                

8-4
Zobaczmy aktywność blokującą

Locking

Locking

Locking

Locking

Locking

SQL Server Lock Resources

SQL Server Lock Resources

SQL Server Lock Resources

SQL Server Lock Resources

SQL Server Lock Resources

Nie wszystkie locki są kompatybilne między sobą.
Inny lock nie może zostać umieszczony gdy zasób ma na sobie lock exclusive
Inne transakcje muszą czekać bądź dostać timeout aby exclusive lock został zwoliony
Jak to działa?

Jak to działa?

Jak to działa?

8-4 Zobaczyć Aktywność blokująca

                    
                        --stwórzmy celowo trazakcje która nie jest zamknięta

                        USE AdventureWorks2014;
                        BEGIN TRAN
                        SELECT ProductID, ModifiedDate
                        FROM Production.ProductDocument WITH (TABLOCKX);
                    
                

8-4-1 Zobaczyć Aktywność blokująca

                    
                        --w drugim oknie

                        SELECT sessionid = request_session_id ,
                        ResType = resource_type ,
                        ResDBID = resource_database_id ,
                        ObjectName = OBJECT_NAME(resource_associated_entity_id, 
                        resource_database_id) ,
                        
                        RMode = request_mode ,
                        RStatus = request_status
                        FROM sys.dm_tran_locks
                        WHERE resource_type IN ('DATABASE', 'OBJECT');
                        GO
                        
                    
                

blog
Copyright © Cezary Walenciuk
8-5
Kontrola na blokowaniem Tabelki

8-5 Kontrola na blokowaniem Tabelki

                    
                        USE AdventureWorks2014;
                        GO
                            ALTER TABLE Person.Address
                            SET ( LOCK_ESCALATION = AUTO );
                            SELECT lock_escalation,lock_escalation_desc
                            FROM sys.tables WHERE name='Address';
                        GO
                        
                    
                

LOCK_ESCALATION =

8-5 Kontrola na blokowaniem Tabelki

                    
                        USE AdventureWorks2014;
                        GO
                            ALTER TABLE Person.Address
                            SET ( LOCK_ESCALATION = DISABLE);
                            SELECT lock_escalation,lock_escalation_desc
                            FROM sys.tables WHERE name='Address';
                        GO
                    
                

8-6
Konfiguracja poziomu sesji transakcynej

ANSI/ISO SQL definiuje 4 typy interakcji pomiędzy transakcjami

ANSI/ISO SQL definiuje 4 typy interakcji pomiędzy transakcjami

8-6 Konfiguracja poziomu sesji transakcynej

                    
                        SET TRANSACTION ISOLATION LEVEL 
                        {   
                            READ UNCOMMITTED 
                            | READ COMMITTED
                            REPEATABLE READ
                            SNAPSHOT | SERIALIZABLE 
                        }
                    
                

SQL Server Isolation Levels

8-6 READ COMMITTED

                    
                        session1> NoweOkno;
                        session1> SELECT firstname FROM names WHERE id = 7;
                        Aaron
                        session2> BEGIN Transation
                        session2> UPDATE names SET firstname = 'Bob' WHERE id = 7;
                        session2> SELECT firstname FROM names WHERE id = 7;
                        Bob
                        session1> SELECT firstname FROM names WHERE id = 7;
                        ................
                        session2> COMMIT;
                        session1> Bob
                    
                

SQL Server Isolation Levelsi

8-6 READ UNCOMMITTED

                    
                        session1> Nowe okno
                        session1> SELECT firstname FROM names WHERE id = 7;
                        Aaron

                        session2> BEGIN Transation;
                        session2> SELECT firstname FROM names WHERE id = 7;
                        Aaron
                        session2> UPDATE names SET firstname = 'Bob' WHERE id = 7;
                        session2> SELECT firstname FROM names WHERE id = 7;
                        Bob
                        session1> SELECT firstname FROM names WHERE id = 7;
                        Bob
                        session2> COMMIT;
                        
                        session1> SELECT firstname FROM names WHERE id = 7;
                        Bob
                    
                

SQL Server Isolation Levelsi

8-6 REPEATABLE READ

                    
                        session1> Nowe okno
                        session1> SELECT firstname FROM names WHERE id = 7;
                        Aaron
                        
                        session2> BEGIN Transation;
                        session2> SELECT firstname FROM names WHERE id = 7;
                        Aaron
                        session2> UPDATE names SET firstname = 'Bob' WHERE id = 7;
                        session2> SELECT firstname FROM names WHERE id = 7;
                        Bob
                        session2> COMMIT;
                        
                        session1> SELECT firstname FROM names WHERE id = 7;
                        Aaron
                    
                

SQL Server Isolation Levelsi

8-6 SERIALIZABLE

                    
                        session1> BEGIN Transation;
                        session1> SELECT firstname FROM names WHERE id = 7;
                        Aaron
                        
                        session2> BEGIN Transation;
                        session2> SELECT firstname FROM names WHERE id = 7;
                        Aaron
                        session2> UPDATE names SET firstname = 'Bob' WHERE id = 7;
                        session2> ...
                        session2> ...
                        
                        session1> END;
                        session2> UPDATE Done
                    
                

SQL Server Isolation Levels

8-6
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE

8-6 Konfiguracja poziomu sesji transakcynej

                    
                        --pierwsze okno
                        USE AdventureWorks2014;
                        GO
                        SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
                        GO
                            BEGIN TRANSACTION
                            SELECT AddressTypeID, Name
                            FROM Person.AddressType
                            WHERE AddressTypeID BETWEEN 1 AND 6;
                        GO
                    
                

8-6-1 Konfiguracja poziomu sesji transakcynej

                    
                        --drugie okno
                        SELECT resource_associated_entity_id, resource_type,
                        request_mode, request_session_id
                        FROM sys.dm_tran_locks;
                        GO
                    
                

8-6-2 Konfiguracja poziomu sesji transakcynej

                    
                        --TRZECIE okno
                        Update Person.AddressType
                        SET Name = 'T'
                        WHERE AddressTypeID = 1 
                        GO
                    
                

8-6-3 Konfiguracja sesji transakcynej

                    
                        --USE AdventureWorks2014;
                        --GO
                        --SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
                        --GO
                        --    BEGIN TRANSACTION
                        --    SELECT AddressTypeID, Name
                        --    FROM Person.AddressType
                        --    WHERE AddressTypeID BETWEEN 1 AND 6;
                        --GO

                        COMMIT TRANSACTION;
                    
                

8-6-5
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;

8-6-5 Konfiguracja sesji transakcynej

                    
                        USE AdventureWorks2014;
                        GO
                        SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
                        GO
                            BEGIN TRANSACTION
                            SELECT AddressTypeID, Name
                            FROM Person.AddressType
                            WHERE AddressTypeID BETWEEN 1 AND 6;
                        GO
                    
                

8-6-6 Konfiguracja poziomu sesji transakcynej

                    
                        SELECT resource_associated_entity_id, resource_type,
                        request_mode, request_session_id
                        FROM sys.dm_tran_locks;
                        GO
                    
                

blog
Copyright © Cezary Walenciuk

8-6-6 Konfiguracja sesji transakcynej

                    
                        --USE AdventureWorks2014;
                        --GO
                        --SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
                        --GO
                        --    BEGIN TRANSACTION
                        --    SELECT AddressTypeID, Name
                        --    FROM Person.AddressType
                        --    WHERE AddressTypeID BETWEEN 1 AND 6;
                        --GO

                        COMMIT TRANSACTION;
                    
                

8-6-7
SET TRANSACTION ISOLATION LEVEL SNAPSHOT;

8-6-7 Konfiguracja sesji transakcynej

                    
                        ALTER DATABASE AdventureWorks2014
                        SET ALLOW_SNAPSHOT_ISOLATION ON;
                        GO
                        USE AdventureWorks2014;
                        GO
                        SET TRANSACTION ISOLATION LEVEL SNAPSHOT;
                        GO
                            BEGIN TRANSACTION
                            SELECT CurrencyRateID,EndOfDayRate
                            FROM Sales.CurrencyRate
                            WHERE CurrencyRateID = 8317;
                        GO
                    
                

8-6-8 Konfiguracja sesji transakcynej

                    
                        -- w innym oknie 

                        USE AdventureWorks2014;
                        GO
                        UPDATE Sales.CurrencyRate
                        SET EndOfDayRate = 1.00
                        WHERE CurrencyRateID = 8317;
                        GO
                    
                

8-6-9 Konfiguracja sesji transakcynej

                    
                        -- w oknie transakcji

                        SELECT CurrencyRateID,EndOfDayRate
                        FROM Sales.CurrencyRate
                        WHERE CurrencyRateID = 8317;
                        GO
                    
                

8-6-10 Konfiguracja sesji transakcynej

                    
                        -- w oknie transakcji

                        COMMIT TRANSACTION;
                        SELECT CurrencyRateID,EndOfDayRate
                        FROM Sales.CurrencyRate
                        WHERE CurrencyRateID = 8317;
                        GO
                    
                

8-7
Szukanie blokady i jej usuwanie
Blokowanie

Dlaczego blokowanie może nastąpić

Dlaczego blokowanie może nastąpić

8-7 Szukanie blokady i jej usuwanie

                    
                        KILL {SPID | UOW} [WITH STATUSONLY]
                    
                

KILL Command Arguments

8-7 Szukanie blokady i jej usuwanie

                    
                        --na jednym oknie
                        USE AdventureWorks2014;
                        GO
                        BEGIN TRAN
                        UPDATE Production.ProductInventory
                        SET Quantity = 400
                        WHERE ProductID = 1 AND LocationID = 1;
                    
                

8-7-2 Szukanie blokady i jej usuwanie

                    
                        --w drugim oknie
                        USE AdventureWorks2014;
                        GO
                        BEGIN TRAN
                        UPDATE Production.ProductInventory
                        SET Quantity = 406
                        WHERE ProductID = 1 AND LocationID = 1;
                    
                

8-7-3 Szukanie blokady i jej usuwanie

                    
                        --w trzecim oknie
                        SELECT blocking_session_id, wait_duration_ms, session_id
                        FROM sys.dm_os_waiting_tasks
                        WHERE blocking_session_id IS NOT NULL;
                        GO
                    
                

blog
Copyright © Cezary Walenciuk

8-7 Szukanie blokady i jej usuowanie

                    
                        --w czwartym oknie
                        SELECT t.text
                        FROM sys.dm_exec_connections c
                        CROSS APPLY sys.dm_exec_sql_text (c.most_recent_sql_handle) t
                        WHERE c.session_id = 55; 
                        --użyj blocking_session_id z poprzedniego zapytania
                        GO
                    
                

blog
Copyright © Cezary Walenciuk

8-7-4 Szukanie blokady i jej usuowanie

                    
                        KILL 55;
                    
                

8-8
Konfiguranie tego jak długo wyrażenie może przetrzymać lock, aż do jego wyzwolenia

8-8 Konfiguranie tego jak długo wyrażenie może przetrzymać lock, aż do jego wyzwolenia

                    
                        SET LOCK_TIMEOUT timeout_period
                    
                

8-8 Konfiguranie tego jak długo wyrażenie może przetrzymać lock, aż do jego wyzwolenia

                    
                        SET LOCK_TIMEOUT timeout_period
                    
                

8-8-1 Konfiguranie tego jak długo wyrażenie może przetrzymać lock, aż do jego wyzwolenia

                    
                        --w pierwszym oknie
                        USE AdventureWorks2014;
                        GO
                        BEGIN TRAN
                        UPDATE Production.ProductInventory
                        SET Quantity = 400
                        WHERE ProductID = 1 AND LocationID = 1;
                    
                

8-8-2 Konfiguranie tego jak długo wyrażenie może przetrzymać lock, aż do jego wyzwolenia

                    
                        --w drugim oknie
                        USE AdventureWorks2014;
                        GO
                        SET LOCK_TIMEOUT 5000;
                        UPDATE Production.ProductInventory
                        SET Quantity = 406
                        WHERE ProductID = 1 AND LocationID = 1;
                    
                

Deadlock

Jak Deadlock może nastąpić?

8-9
Szukanie deadlock-u poprzez Extended Events

8-9 Szukanie deadlock-u poprzez Extended Events

                    
                        --pierwsze okno
                        USE AdventureWorks2014;
                        GO
                        SET NOCOUNT ON;
                        SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
                        WHILE 1=1
                        BEGIN
                            BEGIN TRAN
                                UPDATE Purchasing.Vendor
                                SET CreditRating = 1
                                WHERE BusinessEntityID = 1494;
                                UPDATE Purchasing.Vendor
                                SET CreditRating = 2
                                WHERE BusinessEntityID = 1492;
                            COMMIT TRAN
                        END
                    
                

8-9-2 Szukanie deadlock-u poprzez Extended Events

                    
                        --drugie okno
                        USE AdventureWorks2014;
                        GO
                        SET NOCOUNT ON;
                        WHILE 1=1
                        BEGIN
                        BEGIN TRANSACTION
                            UPDATE Purchasing.Vendor
                            SET CreditRating = 2
                            WHERE BusinessEntityID = 1492;
                            UPDATE Purchasing.Vendor
                            SET CreditRating = 1
                            WHERE BusinessEntityID = 1494;
                            COMMIT TRANSACTION
                        END
                    
                

8-9-3 Szukanie deadlock-u poprzez Extended Events

                    
                        --trzecie okno

                        CREATE EVENT SESSION [Deadlock] ON SERVER
                        ADD EVENT sqlserver.lock_deadlock(
                        ACTION(sqlserver.database_name,sqlserver.plan_handle,sqlserver.sql_text)),
                        ADD EVENT sqlserver.xml_deadlock_report
                        ADD TARGET package0.event_file(SET filename=N'D:\Deadlock.xel')

                        --Upewnij się, że masz dostęp i uprawienia do ścieżki

                        WITH (STARTUP_STATE=ON)
                        GO
                        ALTER EVENT SESSION Deadlock
                        ON SERVER
                        STATE = START;
                    
                

8-9-4 Szukanie deadlock-u poprzez Extended Events

                    
                        --czwarte okno

                        SELECT TargetData AS DeadlockGraph
                        FROM
                        (SELECT CAST(event_data AS xml) AS TargetData
                        FROM sys.fn_xe_file_target_read_file
                        ('D:\Deadlock*.xel',NULL,NULL, NULL)
                        )
                        AS Data
                        WHERE 
                        TargetData.value('(event/@name)[1]', 'varchar(50)') = 'xml_deadlock_report';
                    
                

8-9-3 Szukanie deadlock-u poprzez Extended Events

                    

                        <event name="xml_deadlock_report" package="sqlserver" timestamp="2020-11-17T12:16:37.572Z">
                        <data name="xml_report">
                          <value>
                            <deadlock>
                              <victim-list>
                                <victimProcess id="process177af683088" />
                              </victim-list>
                              <process-list>
                                <process id="process177af683088" taskpriority="0" 
                                logused="144" waitresource="KEY: 5:72057594049789952 (b4903b2250cc)" 
                                waittime="3521" ownerId="468635" transactionname="user_transaction" 
                                lasttranstarted="2020-11-17T13:16:34.050" XDES="0x1779f36c428" 
                                lockMode="X" schedulerid="7" kpid="20452" 
                                status="suspended" spid="56" sbid="0" ecid="0" 
                                priority="0" trancount="2" lastbatchstarted="2020-11-17T13:16:34.050" 
                                lastbatchcompleted="2020-11-17T13:16:34.047" lastattention="1900-01-01T00:00:00.047" 
                                clientapp="Microsoft SQL Server Management Studio - Query" hostname="CEZMSI" 
                                hostpid="1476" loginname="CEZMSI\PanNiebieski" 
                                isolationlevel="read committed (2)" xactid="468635" currentdb="5" 
                                currentdbname="AdventureWorks2014" lockTimeout="4294967295" 
                                clientoption1="673187936" clientoption2="390200">
                                  <executionStack>
                                    <frame procname="adhoc" line="8" stmtstart="40" stmtend="200" 
                                    sqlhandle="0x02000000eac1af36f412db4e21d9dcc86feb261fa6bcd2300000000000000000000000000000000000000000">
                      unknown    </frame>
                                    <frame procname="adhoc" line="8" stmtstart="300" 
                                    stmtend="468" sqlhandle="0x020000005312e433857f0fc42c7763c9f49c0ba8feeff51d0000000000000000000000000000000000000000">
                      unknown    </frame>
                                  </executionStack>
                                  <inputbuf>

                    
                

8-9-3 Szukanie deadlock-u poprzez Extended Events

                    
                        
                        <resource-list>
                        <keylock hobtid="72057594049789952" dbid="5" objectname="AdventureWorks2014.Purchasing.Vendor" indexname="PK_Vendor_BusinessEntityID" id="lock177a9200900" mode="X" associatedObjectId="72057594049789952">
                          <owner-list>
                            <owner id="process1779d5c88c8" mode="X" />
                          </owner-list>
                          <waiter-list>
                            <waiter id="process177af683088" mode="X" requestType="wait" />
                          </waiter-list>
                        </keylock>
                        <keylock hobtid="72057594049789952" dbid="5" objectname="AdventureWorks2014.Purchasing.Vendor" indexname="PK_Vendor_BusinessEntityID" id="lock177a9200b80" mode="X" associatedObjectId="72057594049789952">
                          <owner-list>
                            <owner id="process177af683088" mode="X" />
                          </owner-list>
                          <waiter-list>
                            <waiter id="process1779d5c88c8" mode="X" requestType="wait" />
                          </waiter-list>
                        </keylock>
                      </resource-list>
                    
                

blog
Copyright © Cezary Walenciuk
8-10
Ustawienie priorytet do Deadlock

8-10 Ustawienie priorytet do Deadlock

                    
                        SET DEADLOCK_PRIORITY { LOW | NORMAL | HIGH |  }
                    
                

8-10 Ustawienie priorytet do Deadlock

                    
                        SET DEADLOCK_PRIORITY { LOW | NORMAL | HIGH | [numeric-priority] }
                    
                

SET DEADLOCK_PRIORITY Command Arguments

SET DEADLOCK_PRIORITY Command Arguments

8-10 Ustawienie priorytet do Deadlock

                    

                        USE AdventureWorks2014;
                        GO
                        SET NOCOUNT ON;
                        SET DEADLOCK_PRIORITY LOW;

                        WHILE 1=1
                        BEGIN
                        BEGIN TRANSACTION
                        UPDATE Purchasing.Vendor
                        SET CreditRating = 1
                        WHERE BusinessEntityID = 1492;
                        UPDATE Purchasing.Vendor
                        SET CreditRating = 2
                        WHERE BusinessEntityID = 1494;
                        COMMIT TRANSACTION
                        END
                        GO
                    
                

9. Pracowanie ze stringami

Pracowanie ze stringami

Pracowanie ze stringami

Pracowanie ze stringami

Pracowanie ze stringami

Pracowanie ze stringami

Pracowanie ze stringami

Pracowanie ze stringami

Pracowanie ze stringami

Pracowanie ze stringami

9-1
Łączenie napisów

9-1 Łączenie napisów

                    
                        SELECT TOP (15)
                        FullName = 
                        CONCAT(LastName, ', ', FirstName, ' ', MiddleName)
                        FROM Person.Person p;
                    
                

blog
Copyright © Cezary Walenciuk
9-2
Znajdź wartość ASCII

9-2 Znajdź wartość ASCII

                    
                        SELECT ASCII('c'),
                        ASCII('e'),
                        ASCII('z'),
                        ASCII('a'),
                        ASCII('r');

                        SELECT CHAR(99),
                        CHAR(101),
                        CHAR(122),
                        CHAR(97),
                        CHAR(114) ;
                    
                

blog
Copyright © Cezary Walenciuk
9-3
Znajdź wartość cyfrową kodu UNICODE

9-3 Znajdź wartość cyfrową kodu UNICODE

                    
                        SELECT UNICODE('G'),
                        UNICODE('o'),
                        UNICODE('o'),
                        UNICODE('d'),
                        UNICODE('!');

                        SELECT NCHAR(71),
                        NCHAR(111),
                        NCHAR(111),
                        NCHAR(100),
                        NCHAR(33) ;
                    
                

blog
Copyright © Cezary Walenciuk
9-4
Lokalizowanie znaków w stringu

9-4 Lokalizowanie znaków w stringu

                    
                        SELECT CHARINDEX('string to find',
                        'Znajdź mi "string to find" w tym napisie');
                    
                

blog
Copyright © Cezary Walenciuk

9-4 Lokalizowanie znaków w stringu

                    
                        SELECT TOP 18
                        AddressID,
                        AddressLine1,
                        PATINDEX('%[0]%Mt%', AddressLine1)
                        FROM Person.Address
                        WHERE PATINDEX('%[0]%Mt%', AddressLine1) > 0;
                    
                

blog
Copyright © Cezary Walenciuk
9-5
Porównywanie napisów

9-5 Porównywanie napisów

                    
                        SELECT DISTINCT
                        SOUNDEX(LastName),
                        SOUNDEX('Smi'),
                        LastName
                        FROM Person.Person
                        WHERE SOUNDEX(LastName) = SOUNDEX('Smi');
                    
                

blog
Copyright © Cezary Walenciuk
9-6
Zwracanie napisów po lewej i po prawej

9-6 Zwracanie napisów po lewej i po prawej

                    
                        SELECT LEFT('Chce tylko 10 znaków po lewej', 10);

                        SELECT RIGHT('Chce tylko 10 znaków po prawej', 10);
                    
                

blog
Copyright © Cezary Walenciuk

9-6-1 Zwracanie napisów po lewej i po prawej

                    
                        SELECT TOP (18)
                        ProductNumber,
                        ProductName = LEFT(Name, 10),
						ProductName = RIGHT(Name, 10)
                        FROM Production.Product;
                    
                

blog
Copyright © Cezary Walenciuk
9-7
Zwracanie tylko części napisu

9-7 Zwracanie tylko części napisu

                    
                        SELECT TOP (18)
                        PhoneNumber,
                        AreaCode = LEFT(PhoneNumber, 3),
                        Exchange = SUBSTRING(PhoneNumber, 5, 3)
                        FROM Person.PersonPhone
                        WHERE PhoneNumber LIKE 
                        '[0-9][0-9][0-9]-[0-9][0-9][0-9]-[0-9][0-9][0-9][0-9]';
                    
                

blog
Copyright © Cezary Walenciuk
9-8
Liczenie długości napisu

9-8 Liczenie długości napisu

                    
                        SELECT LEN(N'SQL został opracowany w latach 70. w firmie IBM. 
						Stał się standardem w komunikacji z 
						serwerami relacyjnych baz danych.');

                        SELECT DATALENGTH(N'SQL został opracowany w latach 70. w firmie IBM. 
						Stał się standardem w komunikacji z serwerami relacyjnych baz danych.');
                    
                

blog
Copyright © Cezary Walenciuk

9-8-1 Liczenie długości napisu

                    
                        SELECT
                        DATALENGTH(123) as [123],
                        DATALENGTH(123.0) as [123.0],
						DATALENGTH('123') as ['123'],
                        DATALENGTH(GETDATE()) as [GetDate];
                    
                

blog
Copyright © Cezary Walenciuk
9-9
Zastąpienie części napisu

9-9 Zastąpienie części napisu

                    
                        SELECT REPLACE('Pierwszą firmą, która włączyła SQL
                        do swojego produktu komercyjnego, był Oracle.'
                        , 'Oracle', 'Lichy Dzwig');
                    
                

blog
Copyright © Cezary Walenciuk
9-10
Umieść napis w X

9-10 Umieść napis w X

                    
                        SELECT STUFF ( 'Mój kot ma na imię X. Poznałeś go?', 18, 1, 'Stefan' );
                    
                

blog
Copyright © Cezary Walenciuk
9-11
Zmiana wielkości znaków

9-11 Zmiana wielkości znaków

                    
                        SELECT LOWER(DocumentSummary)
                        FROM Production.Document
                        WHERE FileName = 'Installing Replacement Pedals.doc';

                        SELECT UPPER(DocumentSummary)
                        FROM Production.Document
                        WHERE FileName = 'Installing Replacement Pedals.doc';
                    
                

blog
Copyright © Cezary Walenciuk
9-12
Usuwanie i dodawanie białych znaków

9-12 Usuwanie i dodawanie białych znaków

                    
                        SELECT CONCAT('||', 
						LTRIM('         Napis       '), 
                        '||' );

                        SELECT CONCAT('||', 
						RTRIM('         Napis       '),
                         '||' );
                    
                

blog
Copyright © Cezary Walenciuk
9-13
Potwórz znaki wiele razy

9-13 Potwórz znaki wiele razy

                    
                        SELECT REPLICATE ('W', 30) ;
                    
                

blog
Copyright © Cezary Walenciuk
9-14
Potwórz białe znaki wiele razy

9-14 Potwórz białe znaki wiele razy

                    
                        DECLARE @animals TABLE
                        (
							string1 VARCHAR(20),
							string2 VARCHAR(20),
							string3 VARCHAR(20)
                        );

                        INSERT @animals
                        VALUES ('elephant', 'dog', 'giraffe'),
                        ('kitty', 'puppy', 'ant'),
                        ('chicken', 'fish', 'marmacet');

                        SELECT CONCAT(string1, SPACE(40 - LEN(string1)),
                        string2, SPACE(40 - LEN(string2)),
                        string3, SPACE(40 - LEN(string3))) AS a
                        FROM @animals
                    
                

blog
Copyright © Cezary Walenciuk
9-15
Odwrócenie kolejności znaków

9-15 Odwrócenie kolejności znaków

                    
                        SELECT REVERSE('Jak Programowac');
                    
                

blog
Copyright © Cezary Walenciuk
Podsumowanie
Dzięki za obecność