Ira Sharenow Consulting

Ira Sharenow ConsultingIra Sharenow ConsultingIra Sharenow Consulting
  • Home
  • R Stat
  • SQL
  • Tableau
  • Excel
  • About Ira
  • Contact
  • More
    • Home
    • R Stat
    • SQL
    • Tableau
    • Excel
    • About Ira
    • Contact

Ira Sharenow Consulting

Ira Sharenow ConsultingIra Sharenow ConsultingIra Sharenow Consulting
  • Home
  • R Stat
  • SQL
  • Tableau
  • Excel
  • About Ira
  • Contact

SQL Query Link

SQL Queries by Ira Sharenow 202302 (txt)

Download

SQL Query Link version 2

/*

Title: SQL Queries by Ira Sharenow 

Author: Ira Sharenow

Creation Date: February 6, 2023


In order to demonstrate a wide variety of SQL query techniques, I created some data in Excel CSV format.

I then read the data into SQL Server using a database named web2023.

I explored T-SQL by writing a large number of queries.

Below I list the tables.

Then I display much of the data.

Then I write more complex queries. Often I display some or all of the output.

Sometimes I solve a problem in more than  one way, such as writing a subquery and also

using window functions.



 The tables

 1. employees

 2. products

 3. customers

 4. orderDetails

 5. orders

 */


 -- Displaying the data


 USE web2023;


-- Query 1A

SELECT *

FROM employees;

/*

empID firstName lastName

1 Al Jones

2 Barb Smith

3 Carol Johnson

4 Dave Adams

*/


-- Query 1B


SELECT *

FROM products;

/*

prodID product

101 baseball

102 basketball

103 soccer ball

104 football

*/


-- Query 1C

SELECT *

FROM customers;

/*

custid name Country

51 Ellen USA

52 Fran USA

53 George USA

54 Helen USA

55 Ira USA

56 John Canada

57 Jack Canada

58 Kim Canada

59 James Mexico

60 Lucy Mexico

61 Mary Mexico

*/




-- Query 1D

SELECT *

FROM orderDetails;


/*

Sometimes a customer bought multiple items in the same order

1020 rows of output

orderid productid unitprice qty

1001 101 10.00 9

1002 101 10.00 10

1003 101 10.00 12

1004 101 10.00 15

1005 101 10.00 15

1006 101 10.00 10

1007 101 10.00 14

1008 101 10.00 13

1009 101 10.00 5

1010 101 10.00 14

1001 102 20.00 3

1002 102 20.00 9

*/


-- Query 1E

SELECT *

FROM orders;

/*

1000 rows of output

orderid custid empid orderdate shipcountry

1001 60 1 2021-04-14 USA

1002 59 1 2020-07-04 USA

1003 52 1 2021-09-30 USA

1004 51 2 2019-09-12 USA

1005 54 4 2019-11-19 USA

1006 60 3 2019-02-10 USA

1007 58 3 2019-10-08 USA

...

1599 56 1 2019-11-21 Canada

1600 56 1 2021-01-07 Canada

1601 55 3 2021-07-28 Mexico

1602 51 4 2021-03-17 Mexico

1603 58 2 2019-06-22 Mexico

*/




-- Query 2

-- Numbers of customers

-- Answer: 11

SELECT COUNT(custid) AS customerCount

FROM customers;


-- Query 3

-- Number of customers who have placed orders

-- Answer: 10

SELECT COUNT(DISTINCT c.custid) AS customerCount

FROM customers AS c

  LEFT JOIN orders AS o

    ON c.custid = o.custid

WHERE o.custid IS NOT NULL;


-- Query 4

-- ID and name of customer who has not yet ordered

-- Answer: Mary

SELECT c.custid, c.name

FROM customers AS c

  LEFT JOIN orders AS o

    ON c.custid = o.custid

WHERE o.custid IS NULL;



-- Query 5

-- Number of orders by year. 

-- Answer: 2019 331

--         2020 315

--         2021 354


SELECT YEAR(orderdate) AS year, COUNT(DISTINCT orderid) as totalSales

FROM orders

GROUP BY YEAR(orderdate);


-- Query 6A

-- Number of orders by year and ship country.

-- Note that there was some missing data.


SELECT shipcountry, YEAR(orderdate) AS year, COUNT(DISTINCT orderid) as totalSales

FROM orders

GROUP BY shipcountry, YEAR(orderdate);

/*

shipcountry year totalSales

NULL 2019 2

Canada 2019 32

Mexico 2019 142

USA 2019 155

NULL 2020 1

Canada 2020 32

Mexico 2020 127

USA 2020 155

NULL 2021 2

Canada 2021 36

Mexico 2021 131

USA 2021 185

*/


-- Query 6B

-- Number of orders by year and ship country. Results pivoted so each year has its own column

-- Nulls placed last


WITH first AS

(

SELECT shipcountry, YEAR(orderdate) AS year, COUNT(DISTINCT orderid) as totalSales

FROM orders

GROUP BY shipcountry, YEAR(orderdate)

)

SELECT shipcountry,

  MAX(CASE WHEN year = 2019 THEN totalSales END) AS [2019],

  MAX(CASE WHEN year = 2020 THEN totalSales END) AS [2020],

  MAX(CASE WHEN year = 2021 THEN totalSales END) AS [2021]

FROM first

GROUP BY shipcountry

ORDER BY CASE 

    WHEN shipcountry IS NULL THEN 2 

ELSE 1 

END,  

shipcountry;



-- Query 6C

-- Number of orders by year and ship country. Results pivoted so each year has its own column

-- Using T-SQL pivot operator

-- Nulls placed last


WITH first AS

(

SELECT shipcountry, YEAR(orderdate) AS year, COUNT( orderid) as totalSales

FROM orders

GROUP BY shipcountry, YEAR(orderdate)

)

SELECT shipcountry, [2019], [2020], [2021]

FROM 

   (SELECT shipcountry, year, totalSales

    FROM first) AS D

  PIVOT(MAX(totalSales) FOR year IN ([2019], [2020], [2021])) AS P

ORDER BY CASE 

    WHEN shipcountry IS NULL THEN 2 

ELSE 1 

END,  

shipcountry;


-- Query 6D

-- Number of orders by year and ship country. All 4 groupings in one query

SELECT shipcountry, YEAR(orderdate) AS year, COUNT( orderid) as totalSales

FROM orders

GROUP BY

   GROUPING SETS 

    (

 ((shipcountry), YEAR(orderdate)),

 (shipcountry), (YEAR(orderdate)), ()

);



-- Query 6E

-- Number of orders by year and ship country. All 4 groupings in one query using CUBE syntax

SELECT shipcountry, YEAR(orderdate) AS year, COUNT( orderid) as totalSales

FROM orders

GROUP BY CUBE (shipcountry, YEAR(orderdate));

 


-- Query 7A

-- Top 5 orders by qty. Break ties by selecting most recent


SELECT TOP(5) od.orderid, od.productid, od.unitprice, od.qty, o.orderDate

FROM orderDetails AS od

  INNER JOIN orders AS o

    ON od.orderid = o.orderid

ORDER BY qty DESC, orderDate DESC;

/*

orderid productid unitprice qty orderDate

1658 104 40.00 15 2021-12-16

1618 103 30.00 15 2021-11-12

1106 102 20.00 15 2021-11-02

1383 104 40.00 15 2021-10-09

1257 101 10.00 15 2021-10-06

*/


-- Query 7B

-- Top 5 orders by qty. Break ties by selecting most recent. Now add customer and employee


SELECT TOP(5) c.name AS custName, e.firstname AS empFirst, e.lastname AS empLast, 

              od.orderid, productid, unitprice, qty, o.orderDate

FROM orderDetails AS od

  INNER JOIN orders AS o

    ON od.orderid = o.orderid

  INNER JOIN customers AS c

    on o.custid = c.custid

  INNER JOIN employees AS e

    ON o.empid = e.empid

ORDER BY qty DESC, orderDate DESC;


/*

custName empFirst empLast orderid productid unitprice qty orderDate

Helen Barb Smith 1658 104 40.00 15 2021-12-16

John Al Jones 1618 103 30.00 15 2021-11-12

Kim Barb Smith 1106 102 20.00 15 2021-11-02

James Al Jones 1383 104 40.00 15 2021-10-09

Lucy Al Jones 1257 101 10.00 15 2021-10-06


*/



-- Query 7C

-- Top 5 orders by qty. Break ties by selecting most recent. Now add customer and employee

-- Alternative: use OFFSETFETCH

SELECT c.name AS custName, e.firstname AS empFirst, e.lastname AS empLast, 

              od.orderid, productid, unitprice, qty, o.orderDate

FROM orderDetails AS od

  INNER JOIN orders AS o

    ON od.orderid = o.orderid

  INNER JOIN customers AS c

    on o.custid = c.custid

  INNER JOIN employees AS e

    ON o.empid = e.empid

ORDER BY qty DESC, orderDate DESC

OFFSET 0 ROWS FETCH NEXT 5 ROWS ONLY;


-- Query 7D

-- Top 5 orders by qty. Break ties by selecting most recent. Now add customer and employee

-- Alternative: use Window functions



WITH first AS

(

SELECT c.name AS custName, e.firstname AS empFirst, e.lastname AS empLast, 

              od.orderid, productid, unitprice, qty, o.orderDate,

 ROW_NUMBER() OVER(ORDER BY qty DESC, orderDate DESC) AS rn

FROM orderDetails AS od

  INNER JOIN orders AS o

    ON od.orderid = o.orderid

  INNER JOIN customers AS c

    on o.custid = c.custid

  INNER JOIN employees AS e

    ON o.empid = e.empid


)

SELECT *

FROM first

WHERE rn <= 5

ORDER BY qty DESC, orderDate DESC;



-- Query 8

-- Skip top 200 orders by qty and now get the orders that rank 201-210. Break ties by selecting most recent. 


SELECT c.name AS custName, e.firstname AS empFirst, e.lastname AS empLast, 

              od.orderid, productid, unitprice, qty, o.orderDate

FROM orderDetails AS od

  INNER JOIN orders AS o

    ON od.orderid = o.orderid

  INNER JOIN customers AS c

    on o.custid = c.custid

  INNER JOIN employees AS e

    ON o.empid = e.empid

ORDER BY qty DESC, orderDate DESC

OFFSET 200 ROWS FETCH NEXT 10 ROWS ONLY;



/*

custName empFirst empLast orderid productid unitprice qty orderDate

Lucy Barb Smith 1700 103 30.00 12 2021-03-01

Kim Carol Johnson 1918 103 30.00 12 2021-02-19

Ellen Carol Johnson 1079 102 20.00 12 2021-02-18

Lucy Barb Smith 1763 102 20.00 12 2021-01-11

Kim Barb Smith 1285 101 10.00 12 2021-01-03

Ellen Barb Smith 1476 103 30.00 12 2020-12-28

Lucy Al Jones 1771 102 20.00 12 2020-12-01

John Carol Johnson 1842 102 20.00 12 2020-10-30

Fran Carol Johnson 1395 104 40.00 12 2020-10-21

George Carol Johnson 1808 104 40.00 12 2020-10-15

*/


-- Query 9

-- GET names of customers with at least 100 orders


 SELECT c.custid, c.name AS custName, COUNT(orderid) AS numorders

 FROM orders AS o

   INNER JOIN customers AS c

     ON o.custid = c.custid

 GROUP BY c.custid, c.name

 HAVING  COUNT(orderid) >= 100

 ORDER BY numorders DESC;


-- Query 10

-- Get basic data on all sales that were 1, 2, 3, 4, 5 days before December 25, 2021

-- case when 1 then 'one day early' etc

SELECT o.orderid, o.custid, o.empid, o.orderdate, o.shipcountry,

       CASE 

        WHEN DATEDIFF(day, o.orderdate, '20211225') = 1 THEN '1 day before'

WHEN DATEDIFF(day, o.orderdate, '20211225') = 2 THEN '2 days before'

WHEN DATEDIFF(day, o.orderdate, '20211225') = 3 THEN '3 days before'

WHEN DATEDIFF(day, o.orderdate, '20211225') = 4 THEN '4 days before'

WHEN DATEDIFF(day, o.orderdate, '20211225') = 5 THEN '5 days before'

END AS daysBefore

FROM orders AS o

WHERE DATEDIFF(day, o.orderdate, '20211225') <= 5 AND  DATEDIFF(day, orderdate, '20211225') > 0

ORDER BY o.orderdate DESC;



-- Query 11

-- orders placed on last days of months in 2021

SELECT o.orderid, o.custid, o.empid, o.orderdate, o.shipcountry

FROM orders AS o

WHERE o.orderdate = EOMONTH(o.orderdate)

   AND o.orderdate >= '20210101'

   AND o.orderdate < '20220101'

ORDER BY o.orderdate, o.orderid;


-- Query 12

-- Get max order as measured by value. Note a sale may appear in several rows if multiple items were purchased

WITH first AS

(

 SELECT orderid, SUM(unitprice*qty) AS totalSale

 FROM orderDetails

 GROUP BY orderid

 )

 SELECT MAX(totalSale) AS maxSale

 FROM first AS f;



-- Query 13 

-- Get max order for each customer as measured by value.


WITH first AS

(

 SELECT DISTINCT o.custid, c.name AS custName, od.orderid, 

        SUM(unitprice*qty) OVER(PARTITION BY o.custid, od.orderid) AS totalSale,

ROW_NUMBER() OVER(PARTITION BY o.custid, od.orderid ORDER BY unitprice*qty DESC) AS rnk

 FROM orderDetails AS od

   INNER JOIN orders AS o

   ON od.orderid = o.orderid

   INNER JOIN customers AS c

   ON o.custid = c.custid

WHERE o.custid IS NOT NULL

)

SELECT custid, custName, MAX(totalSale) maxSale

FROM first

WHERE rnk = 1

GROUP BY custid, custName

ORDER BY custid;



-- Query 14 

-- For each customer compute the amount the order is out of the total for that customer

-- Use subquery



SELECT c1.custid, od1.orderid, od1.productid, od1.unitprice*od1.qty AS saleValue,

    CAST(100. * unitprice*od1.qty / (SELECT SUM(od2.unitprice*od2.qty)

                                     FROM orderDetails AS od2 

   INNER JOIN orders AS o2

 ON od2.orderid = o2.orderid

 INNER JOIN customers AS c2

   ON o2.custid = c2.custid

WHERE c2.custid = c1.custid)

   AS NUMERIC(5,2)) AS pct

FROM orderdetails AS od1

  INNER JOIN orders AS o1

    ON od1.orderid = o1.orderid

 INNER JOIN customers AS c1

   ON o1.custid = c1.custid

ORDER BY o1.custid;


-- Query 15A

-- Customers from Mexico who placed orders

-- Recall that Mary is from Mexico but she did not place any orders


SELECT c.name

FROM customers AS c

WHERE c.country = 'Mexico'

  AND c.custid IN

   (SELECT o.custid

    FROM orders AS o

   )


-- Query 15B

-- Using EXIST


SELECT c.name

FROM customers AS c

WHERE c.country = 'Mexico'

  AND EXISTS

   (SELECT *

    FROM orders AS o

WHERE o.custid = c.custid);

   


/*

name

James

Lucy

*/






-- Query 16A

-- Get the running totals for sales values for all orders when ordered by date with

-- orderid and productID as tie breakers

-- Solution using subqueries

SELECT o.custid, o.orderid, od.productid, o.orderdate, od.unitprice*od.qty AS total,

  (SELECT SUM(od2.unitprice*od2.qty)  

   FROM orderDetails AS od2

     INNER JOIN orders AS o2

   ON od2.orderid = o2.orderid

   WHERE o2.orderdate <= o.orderdate

   ) AS runningTotal

FROM orders AS o

  INNER JOIN orderDetails AS od

    ON o.orderid = od.orderid

ORDER BY o.orderdate, o.orderid, od.productid;


-- Query 16B

-- Solution using window functions 

SELECT o.custid, o.orderid, od.productid, o.orderdate, od.unitprice*od.qty AS total,

  SUM(od.unitprice*od.qty) OVER(ORDER BY o.orderdate, o.orderid, od.productid

      ROWS BETWEEN UNBOUNDED PRECEDING

                         AND CURRENT ROW) AS runTotal

FROM orders AS o

  INNER JOIN orderDetails AS od

    ON o.orderid = od.orderid

ORDER BY o.orderdate, o.orderid, od.productid;


-- Query 16C

-- Running totals for each customer

-- Solution using window functions 

-- Do not include data where custid is missing

SELECT o.custid, o.orderid, od.productid, o.orderdate, od.unitprice*od.qty AS total,

  SUM(od.unitprice*od.qty) OVER(PARTITION BY o.custid ORDER BY o.orderdate, o.orderid, od.productid

      ROWS BETWEEN UNBOUNDED PRECEDING

                         AND CURRENT ROW) AS runTotal

FROM orders AS o

  INNER JOIN orderDetails AS od

    ON o.orderid = od.orderid

WHERE o.custid IS NOT NULL

ORDER BY o.custid, o.orderdate, o.orderid, od.productid;



-- Query 17

SELECT DISTINCT o.custid, c.name

FROM orders AS o

  INNER JOIN customers AS c

    ON o.custid = c.custid

WHERE o.custid NOT IN

(

  SELECT o2.custid

  FROM orders AS o2

  WHERE o2.orderdate >= '20211201' 

    AND o2.orderdate <= '20211231' 

)

ORDER BY c.name;

/*

custid name

58 Kim

*/




-- Query 18

-- Number of days since previous order

SELECT orderdate, empid, custid,orderid,

  LAG(orderdate)  OVER(PARTITION BY custid

  ORDER BY orderdate) AS prevorderdate,

  DATEDIFF(day, LAG(orderdate)  OVER(PARTITION BY custid

  ORDER BY orderdate), orderdate) AS day_diff

FROM Orders

WHERE custid IS NOT NULL

ORDER BY custid, orderdate;


-- Query 19A

-- Previous and next order using subqueries

-- Please note that subqueries are much slower than window functions

SELECT orderdate, empid, custid,orderid,

  (SELECT MAX(o2.orderid)

   FROM orders AS O2

   WHERE o2.orderid < o1.orderid

     AND o2.custid = o1.custid

AND o2.custid IS NOT NULL) AS prevorderid,

  (SELECT MIN(o3.orderid)

   FROM orders AS o3

   WHERE o3.orderid > o1.orderid

     AND o3.custid = o1.custid

AND o3.custid IS NOT NULL) AS nextorderid

FROM Orders AS o1

WHERE o1.custid IS NOT NULL

ORDER BY o1.custid, o1.orderid;


-- Query 19B

-- Previous and next order using window functions

SELECT orderdate, empid, custid,orderid,

       LAG(orderid)  OVER(PARTITION BY custid

  ORDER BY orderid) AS prevorderid,

  LEAD(orderid)  OVER(PARTITION BY custid

  ORDER BY orderid) AS nextorderid

FROM Orders

WHERE custid IS NOT NULL

ORDER BY custid, orderid;



-- Query 20

-- Get the employee name for orders missing custid or shipcountry


SELECT o.orderid, e.firstName + ' ' + e.lastName AS employeeName

FROM orders AS o

  INNER JOIN employees AS e

    ON o.empid = e.empID

WHERE o.custid IS NULL

  OR o.shipcountry IS NULL

ORDER BY o.orderid;




-- Query 21

-- The details for every order

-- Full outer join


SELECT o.orderid, o.custid, o.empid, 

       od.productid,

       o.orderdate, o.shipcountry,

       c.name AS custName, c.Country AS custCountry,

  e.firstName + ' ' + e.lastName AS empName,

  p.product, p.price,

  od.qty

FROM orders AS o

  FULL OUTER JOIN orderDetails AS od

     ON o.orderid = od.orderid

  FULL OUTER JOIN customers AS c

     ON o.custid = c.custid

  FULL OUTER JOIN products AS p

     ON od.productid = p.prodID

  FULL OUTER JOIN employees AS e

     ON o.empid = e.empID;



-- Query 22

-- number of balls sold by type


SELECT p.prodID, p.product, SUM(qty) AS numSold

FROM orderDetails AS od

  INNER JOIN products AS p

    ON od.productid = p.prodID

GROUP BY p.prodID, p.product

  

Copyright © 2022 IRASHARENOW.COM - All Rights Reserved.


This website uses cookies.

We use cookies to analyze website traffic and optimize your website experience. By accepting our use of cookies, your data will be aggregated with all other user data.

DeclineAccept