Tuesday, January 27, 2015

Update dữ liệu với GROUP BY .

-- SQL GROUP BY Statement Quick Syntax - SQL group by count - group by clause
SELECT Color            = COALESCE(Color,'N/A'), -- grouping column
       ColorCount       = COUNT(* ),             -- aggregate function
       AvgListPrice     = AVG(ListPrice)         -- aggregate function
FROM   AdventureWorks2008.Production.Product
GROUP BY Color
ORDER BY Color
/*    Color       ColorCount  AvgListPrice
Black       93          725.121
Blue        26          923.6792
Grey        1           125.00
………
*/
------------

-- SQL Update Inner Join Quick Syntax - Update using two tables
UPDATE pod  SET pod.ModifiedDate = poh.ModifiedDate
FROM AdventureWorks2008.Purchasing.PurchaseOrderHeader poh
  INNER JOIN AdventureWorks2008.Purchasing.PurchaseOrderDetail pod
    ON poh.PurchaseOrderID = pod.PurchaseOrderID
WHERE poh.PurchaseOrderID >= 4000
------------

------------
-- TSQL UPDATE table with GROUP BY Quick Syntax
------------
-- SQL GROUP BY in Update Statement - update using group by & aggregate function
-- SQL select into table create for demo - T-SQL update query with GROUP BY
SELECT DISTINCT YEAR=YEAR(OrderDate), Sales=CONVERT(money,0.0)
INTO tempdb.dbo.RevenueByYear
FROM AdventureWorks2008.Sales.SalesOrderHeader
GO
UPDATE rby SET rby.Sales = g.Total  -- update using table aliases in FROM clause
FROM tempdb.dbo.RevenueByYear rby   -- SQL UPDATE INNER JOIN
INNER JOIN ( SELECT YEAR=YEAR(OrderDate), Total=SUM(TotalDue) -- SUM aggregate
             FROM AdventureWorks2008.Sales.SalesOrderHeader
             GROUP BY YEAR(OrderDate) ) g   -- GROUP BY on year aliased as "g"
ON rby.Year = g.YEAR
GO
SELECT *, SalesCurrency='$'+CONVERT(varchar,Sales,1) FROM tempdb.dbo.RevenueByYear
ORDER BY YEAR
/*
YEAR  Sales             SalesCurrency
2001  14327552.2263     $14,327,552.23
2002  39875505.095      $39,875,505.10
2003  54307615.0868     $54,307,615.09
2004  32196912.4165     $32,196,912.42
*/
DROP TABLE tempdb.dbo.RevenueByYear
GO
------------
USE tempdb;
SELECT Color=ISNULL(Color,'N/A'), ItemCount=0 INTO ProductColor
FROM AdventureWorks2008.Production.Product
GROUP BY Color
GO
-- TSQL update from group by - SQL UPDATE JOIN- SQL update table from group by syntax
UPDATE pc
SET pc.ItemCount = cg.ProductColorCount
FROM ProductColor pc
INNER JOIN (SELECT Color=ISNULL(Color,'N/A'), ProductColorCount=COUNT(*)
            FROM AdventureWorks2008.Production.Product
            GROUP BY Color) cg
ON pc.Color = cg.Color
GO
SELECT * FROM ProductColor
GO
/*
Color             ItemCount
N/A               248
Black             93
Blue              26
Grey              1
Multi             8
Red               38
Silver            43
Silver/Black      7
White             4
Yellow            36
*/
DROP TABLE tempdb.dbo.ProductColor
GO
------------
-- T-SQL group by syntax - group by sum aggregate - group by crosstab query
SELECT YEAR = YEAR(OrderDate),
       COALESCE(CONVERT(VARCHAR,SUM(CASE
                        WHEN DATEPART(QQ,OrderDate) = 1 THEN TotalDue
                                    END),1),'') AS 'Quarter 1',
       COALESCE(CONVERT(VARCHAR,SUM(CASE
                        WHEN DATEPART(QQ, OrderDate) = 2 THEN TotalDue
                                    END),1),'') AS 'Quarter 2',
       COALESCE(CONVERT(VARCHAR,SUM(CASE
                        WHEN DATEPART(QQ, OrderDate) = 3 THEN TotalDue
                                    END),1),'') AS 'Quarter 3',
       COALESCE(CONVERT(VARCHAR,SUM(CASE
                        WHEN DATEPART(QQ, OrderDate) = 4 THEN TotalDue
                                    END),1),'') AS 'Quarter 4'
FROM  AdventureWorks2008.Sales.SalesOrderHeader soh
GROUP BY YEAR(OrderDate)
ORDER BY YEAR(OrderDate)
/* Query results

YEAR  Quarter 1         Quarter 2         Quarter 3         Quarter 4
2001                                      5,850,932.95      8,476,619.28
2002  7,379,686.31      8,210,285.17      13,458,206.13     10,827,327.49
2003  8,550,831.87      10,749,269.37     18,220,131.53     16,787,382.31
2004  14,170,982.55     17,969,750.95     56,178.92  
*/
------------
In the following section, four UPDATE with GROUP BY methods are presented:
derived table, correlated subquery, CTE and subselect.
USE AdventureWorks
GO

-- FIRST SOLUTION: update with group by using a DERIVED TABLE- update from a Group By Clause

 -- Add a new column to table
ALTER TABLE HumanResources.Department
ADD NoOfEmployees int null
GO

-- Update the new column from the GROUP BY derived query DG
-- DG JOINed with the update table - update group clause
-- Inner join group by - sql server update group by - SQL update using join
-- SQL update group by - MSSQL update table with group by
UPDATE DE
SET NoOfEmployees =DG.DeptEmployees
FROM HumanResources.Department DE
INNER JOIN (SELECT D.DepartmentID, COUNT(*) AS DeptEmployees
      FROM HumanResources.EmployeeDepartmentHistory EDH
      JOIN HumanResources.Department D
            ON d.DepartmentID = EDH.DepartmentID
            and EDH.EndDate is null
      JOIN HumanResources.Employee E
            ON EDH.EmployeeID = E.EmployeeID
      GROUP BY D.DepartmentID ) DG
ON DE.DepartmentID = DG.DepartmentID
GO

-- Check results
SELECT * FROM HumanResources.Department
GO

-- Cleanup - remove column from table
ALTER TABLE HumanResources.Department
DROP COLUMN NoOfEmployees
GO

-- SECOND SOLUTION: update with group by applying CORRELATED SUBQUERY

-- Add a new column to table
ALTER TABLE HumanResources.Department
ADD NoOfEmployees int null
GO

-- Update the new column from the GROUP BY correlated subquery
-- the WHERE clause defines the correlation
-- SQL group by within update
UPDATE DE
SET NoOfEmployees = (SELECT COUNT(*) AS DeptEmployees
      FROM HumanResources.EmployeeDepartmentHistory EDH
      JOIN HumanResources.Department D
            ON d.DepartmentID = EDH.DepartmentID
            and EDH.EndDate is null
      JOIN HumanResources.Employee E
            ON EDH.EmployeeID = E.EmployeeID
      WHERE DE.DepartmentID = D.DepartmentID
      GROUP BY D.DepartmentID )
FROM HumanResources.Department DE
GO

-- Check results
SELECT * FROM HumanResources.Department
GO

-- Cleanup - remove just-added column
ALTER TABLE HumanResources.Department
DROP COLUMN NoOfEmployees
GO

------------
-- SQL update group by example for PO and Sales Order counts by year
------------
USE tempdb;
GO
CREATE TABLE AWSummary (
ProfitCenterID int,
FiscalYear int,
POs int,
PODetails int,
SalesOrders int,
SalesOrderDetails int
)
GO

-- SQL insert with select
-- The SELECT uses two group by derived tables
-- Profit Center 1 is the entire company
-- The JOIN assumption is that the [Year]-s are matching
-- SQL inner join group by
INSERT AWSummary (ProfitCenterID, FiscalYear, POs, SalesOrders)
SELECT 1, po.[Year], POCount, SOCount
FROM
(
SELECT  [Year]=YEAR(OrderDate), POCount=COUNT(*)
FROM AdventureWorks.Purchasing.PurchaseOrderHeader
GROUP BY YEAR(OrderDate)
) po
INNER JOIN
(
SELECT  [Year]=YEAR(OrderDate), SOCount=COUNT(*)
FROM AdventureWorks.Sales.SalesOrderHeader
GROUP BY YEAR(OrderDate)
) so
ON po.[Year] = so.[Year]
ORDER BY po.[Year]
GO

-- SQL update with group by for Purchase Orders Detail
-- SQL derived table join is used for the update
UPDATE AWSummary
      SET PODetails = Details
FROM AWSummary s
INNER JOIN
(SELECT [Year]= YEAR(OrderDate), Details= COUNT(*)
FROM AdventureWorks.Purchasing.PurchaseOrderHeader poh
INNER JOIN AdventureWorks.Purchasing.PurchaseOrderDetail pod
on poh.PurchaseOrderID = pod.PurchaseOrderID
GROUP BY YEAR(OrderDate)
) d
ON d.Year = s.FiscalYear
WHERE s.ProfitCenterID = 1
GO

-- SQL update with group by for Sales Orders Detail
-- SQL derived table is used for the update
-- SQL update with join
UPDATE AWSummary
      SET SalesOrderDetails = Details
FROM AWSummary s
INNER JOIN
(SELECT [Year]= YEAR(OrderDate), Details= COUNT(*)
FROM AdventureWorks.Sales.SalesOrderHeader soh
INNER JOIN AdventureWorks.Sales.SalesOrderDetail sod
on soh.SalesOrderID = sod.SalesOrderID
GROUP BY YEAR(OrderDate)
) d
ON d.Year = s.FiscalYear
WHERE s.ProfitCenterID = 1
GO

-- Check results 
SELECT FiscalYear, POs, PODetails,  SalesOrders, SalesOrderDetails
FROM AWSummary
WHERE ProfitCenterID=1
ORDER BY FiscalYear
GO
/* Results

FiscalYear  POs         PODetails   SalesOrders SalesOrderDetails
2001        8           15          1379        5151
2002        272         629         3692        19353
2003        1035        2344        12443       51237
2004        2697        5857        13951       45576
*/

-- Cleanup
DROP TABLE AWSummary
GO
------------

-- THIRD SOLUTION: update group by using a CTE - Common Table Expression

ALTER TABLE HumanResources.Department
ADD NoOfEmployees int null
GO

-- Update the new column from the GROUP BY cte
-- cte JOINed with the update table
-- SQL Server update group by
;WITH cteDeptCount AS
(SELECT D.DepartmentID, COUNT(*) AS DeptEmployees
      FROM HumanResources.EmployeeDepartmentHistory EDH
      JOIN HumanResources.Department D
            ON d.DepartmentID = EDH.DepartmentID
            and EDH.EndDate is null
      JOIN HumanResources.Employee E
            ON EDH.EmployeeID = E.EmployeeID
      GROUP BY D.DepartmentID )
UPDATE DE
SET NoOfEmployees =DC.DeptEmployees
FROM HumanResources.Department DE
INNER JOIN cteDeptCount DC
ON DE.DepartmentID = DC.DepartmentID
GO

-- Check results
SELECT * FROM HumanResources.Department
GO

-- Cleanup - remove just-added column
ALTER TABLE HumanResources.Department
DROP COLUMN NoOfEmployees
GO
------------

-- FOURTH SOLUTION: update with SUBSELECT and GROUP BY

------------
-- SQL update with subselect and group by
------------
USE tempdb;
-- SQL select into create table for example
SELECT DISTINCT   SupervisorName=LastName+', '+FirstName,
                  SupervisorID=e2.EmployeeID, DirectlySupervise = 0
INTO DirectSupervisor
FROM AdventureWorks.HumanResources.Employee e1
INNER JOIN AdventureWorks.HumanResources.Employee e2
      ON e1.ManagerID = e2.EmployeeID
INNER JOIN AdventureWorks.Person.Contact c
      ON e2.ContactID = c.ContactID
ORDER BY SupervisorName
GO
-- SELECT * FROM DirectSupervisor
-- (47 row(s) affected)

SELECT TOP 5 * FROM DirectSupervisor ORDER BY NEWID()
GO
/* Partial results

SupervisorName                SupervisorID      DirectlySupervise
Kleinerman, Christian         49                0
Brown, Jo                     16                0
Kim, Shane                    159               0
Kane, Lori                    197               0
Wright, A. Scott              44                0
*/
-- SQL update with subselect
-- SQL Server update with subselect
UPDATE DirectSupervisor
SET DirectlySupervise = (SELECT COUNT(*)
                        FROM AdventureWorks.HumanResources.Employee e
                        WHERE E.ManagerID = DirectSupervisor.SupervisorID)
GO
-- (47 row(s) affected)

SELECT TOP 5 * FROM DirectSupervisor ORDER BY NEWID()
GO
/* Partial results

SupervisorName                      SupervisorID      DirectlySupervise
Krebs, Peter                        21                22
Sánchez, Ken                        109               6
Barreto de Mattos, Paula            30                5
Bradley, David                      6                 8
Welcker, Brian                      273               3
*/

-- Equivalent update with group by - SQL Server inner join group by
-- SQL Server update with group by
UPDATE dr
SET DirectlySupervise = sc.StaffCount
FROM DirectSupervisor dr
INNER JOIN (SELECT e.ManagerID, StaffCount=COUNT(*)
            FROM AdventureWorks.HumanResources.Employee e
            GROUP BY ManagerID) sc
      ON sc.ManagerID = dr.SupervisorID
GO

-- Cleanup
DROP TABLE tempdb.dbo.DirectSupervisor
GO
------------

Source : sqlusa

No comments:

Post a Comment