AdventureWorks Query - sql

In AdventureWorks 2008, what are some other (better) ways of writing this query:
SELECT DISTINCT o.CustomerID, c.CustomerType,
ISNULL(s.Name, p.FirstName + ' ' + p.LastName) AS Name
FROM Sales.SalesOrderHeader o
INNER JOIN Sales.Customer c
ON c.CustomerID = o.CustomerID
LEFT OUTER JOIN sales.Individual i
ON i.CustomerID = o.CustomerID
LEFT OUTER JOIN sales.Store s
ON s.CustomerID = o.CustomerID
LEFT OUTER JOIN Person.Contact p
ON p.ContactID = i.ContactID
ORDER BY CustomerID
Preferably with the ability to support additional CustomerTypes.
Results look like:
CustomerID CustomerType Name
697 S Brakes and Gears
698 S Western Bike Supplies
699 S Sensational Discount Store
700 S Underglaze and Finish Company
701 S Future Bikes
11000 I Jon Yang
11001 I Eugene Huang
11002 I Ruben Torres
11003 I Christy Zhu

Related

Problem with duplicates in distinct when joining

I'm writing this query:
SELECT DISTINCT(o.id), o.status, p.excelID
FROM orders as o
LEFT JOIN (SELECT DISTINCT(orderId) id, excelID FROM parcels) as p on o.id = p.id
WHERE o.id is not null and p.id is not null
This is example of query records:
id
status
excelID
145
good
4444
145
good
3215
94
bad
9875
81
bad
5784
81
bad
5631
Like you can see i have duplicates in id column even when im using DISTINCT function and how can i write question to query to get records like:
id
status
excelID
145
good
4444
94
bad
9875
81
bad
5784
Incase you are interested in maximum value of excelID in case multiple excelID is available. Try this:
SELECT DISTINCT(o.id), o.status, max(p.excelID) as excelID
FROM orders as o
LEFT JOIN (SELECT DISTINCT(orderId) id, excelID FROM parcels) as p on o.id = p.id
WHERE o.id is not null and p.id is not null
group by o.id, o.status

SQL Query to get value of recent order alongwith data from other tables

I am writing an SQL query to get data from more than 3 tables, but for simplifying the question here I am using a similar scenario with 3 tables.
Table1 Customer (PK-CustomerID, Name)
CustomerID
Name
1
John
2
Tina
3
Sam
Table2 Sales (FK-Id, SalePrice)
ID
SalePrice
1
200.00
2
300.00
3
400.00
Table3 Order (PK-Id, FK-CustomerID, Date, Amount)
Id
CustomerID
Date
Amount
101
1
25-09-2021
30.0
102
1
27-09-2021
40.0
103
2
19-09-2021
60.0
In the output, Date and Amount should be the from most recent Order (latest Date), for a customer
My approach was
Select c.CustomerID, c.Name, s.SalePrice, RecentOrder.Date, RecentOrder.Amount from
Customer as c
LEFT JOIN Sales s ON c.CustomerID = s.ID
LEFT JOIN (SELECT top 1 o.Date, o.Amount, o.CustomerID
FROM Order o, Customer c1 WHERE c1.CustomerID = o.CustomerID ORDER BY o.Date DESC)
RecentOrder ON c.CustomerID = RecentOrder.CustomerID
Output I get
CustomerID, Name, SalePrice, Date, Amount
CustomerID
Name
SalePrice
Date
Amount
1
John
200.00
27-09-2021
40.0
2
Tina
300.00
null
null
3
Sam
400.00
null
null
The output I get includes the most recent order out of all the orders. But I want to get the recent order out of the orders made by that customer
Output Required
CustomerID, Name, SalePrice, Date, Amount
CustomerID
Name
SalePrice
Date
Amount
1
John
200.00
27-09-2021
40.0
2
Tina
300.00
19-09-2021
60.0
3
Sam
400.00
null
null
Instead of subquery in left join, you can check with outer apply.
Check following way
Select c.CustomerID, c.Name, s.SalePrice, RecentOrder.Date, RecentOrder.Amount
from Customer c
LEFT JOIN Sales s ON c.CustomerID = s.ID
OUTER APPLY (
SELECT top 1 o.Date, o.Amount, o.CustomerID
FROM [Order] o
WHERE o.CustomerID = c.CustomerID ORDER BY o.Date DESC) RecentOrder`
You need to pre-aggregate or identify the most recent order for each customer order, your query is selecting 1 row for all orders.
Try the following (untested!)
select c.CustomerID, c.Name, s.SalePrice, o.Date, o.Amount
from Customer c
left join Sales s on c.CustomerID = s.ID
outer apply (
select top (1) date, amount
from [order] o
where o.CustomerId=c.CustomerId
order by Id desc
)o

Sum between 3 linked tables SQL Server

I am trying to pull a sum from linked table.
Order:
OrderID LocationID OrderDate
100 1 1/1/2000
200 2 1/2/2000
OrderedItems:
ID OrderID ItemID
1 100 1
2 200 2
3 200 2
4 100 3
OrderItem:
ItemID ItemName Cost
1 Mobile1 100.00
2 Mobile2 200.00
3 Mobile3 300.00
The Order table is effectively a group of OrderedItems. Each row in OrderedItems links back to OrderItem via the ItemID.
I am trying to add a column to the below query for order total.
Order Number Location Date Ordered Order Total
-------------------------------------------------------
100 Sydney 1/1/2000 400
200 Brisbane 1/2/2000 400
The current query I have is:
SELECT
Order.OrderID AS [Order Number],
OL.Name AS [Location],
Order.OrderDate AS [Date Ordered]
FROM
Order
LEFT JOIN
Office_Locations AS OL ON OL.id = Order.LocationID
I have tried to follow this link however I am needing to link through 3 tables for the values to add.
Any hep would be great!
You're not finding a sum from three tables. You're finding a sum from one table: the OrderItem table. The only trick is getting the JOIN and GROUP BY expressions done correctly to make that column available.
SELECT o.OrderID As [Order Number], l.Name As Location
, o.OrderDate As [Date Ordered], SUM(i.Cost) As [Order Total]
FROM [Order] o
INNER JOIN Office_Locations l on l.id = o.LocationID
INNER JOIN OrderedItems oi on oi.OrderID = o.OrderID
INNER JOIN OrderItem i ON i.ItemID = oi.ItemID
GROUP BY o.OrderID, l.Name, o.OrderDate
SQLFIDDLE
You need to use SUM to get the total Cost:
SQL Fiddle
SELECT
[Order Number] = o.OrderID,
Location = ol.Name,
[Date Ordered] = o.OrderDate,
[Order Total] = SUM(i.Cost)
FROM [Order] o
INNER JOIN OrderedItems oi
ON oi.OrderId = o.OrderId
INNER JOIN OrderItem i
ON i.ItemID = oi.ItemID
LEFT JOIN Office_Locations ol
ON ol.id = o.LocationID
GROUP BY
o.OrderID, o.OrderDate, ol.Name
As commented by Joel Coehoorn, it's more normal to have a quantity field in the OrderedItems table than to repeat them. Following his advise, your OrderedItems table should be:
ID OrderID ItemID Quantity
1 100 1 1
2 200 2 2
3 100 3 1
Additional Notes:
Use meaningful aliases to improve readability.
Refrain from using reserved words as your object names i.e. Order could be renamed as OrderHeader.

sum of sales per postal code group

I have a query where you can see all the sales of a person divided in postal groups. But now I want to have the sum of all the sales per postal group.
I have the query like this:
SELECT
p.LastName,
ROW_NUMBER() OVER (PARTITION BY PostalCode
ORDER BY SUM(s.SalesYTD) DESC) AS 'Row Number',
CAST(s.SalesYTD AS INT) SalesYTD,
a.PostalCode
FROM
Sales.SalesPerson s
INNER JOIN
Person.Person p ON s.BusinessEntityID = p.BusinessEntityID
INNER JOIN
Person.Address a ON a.AddressID = p.BusinessEntityID
GROUP BY
p.LastName, a.PostalCode,s.SalesYTD;
--WHERE TerritoryID IS NOT NULL
--AND SalesYTD <> 0
But how to manage the total of each postal group?
Thank you
This is the ouput:
LastName Row Number SalesYTD PostalCode
Mitchell 1 4251369 98027
Blythe 2 3763178 98027
Carson 3 3189418 98027
Reiter 4 2315186 98027
Vargas 5 1453719 98027
Ansman-Wolfe 6 1352577 98027
Jiang 7 559698 98027
Pak 1 4116871 98055
Varkey Chudukatil 2 3121616 98055
Saraiva 3 2604541 98055
Ito 4 2458536 98055
Valdez 5 1827067 98055
Mensa-Annan 6 1576562 98055
Campbell 7 1573013 98055
Tsoflias 8 1421811 98055
Alberts 9 519906 98055
Abbas 10 172524 98055
So how to get the total of salesYTD of postal code: 98027?
Thank you
To get sales per postal code just:
SELECT PostalCode, SUM(SalesYTD) AS 'Summary sales'
FROM Sales.SalesPerson s
INNER JOIN Person.Person p ON s.BusinessEntityID = p.BusinessEntityID
INNER JOIN Person.Address a ON a.AddressID = p.BusinessEntityID
GROUP BY a.PostalCode
If you want sales of particular PostalCode you can even do it that way:
SELECT SUM(SalesYTD) AS 'Summary sales'
FROM Sales.SalesPerson s
INNER JOIN Person.Person p ON s.BusinessEntityID = p.BusinessEntityID
INNER JOIN Person.Address a ON a.AddressID = p.BusinessEntityID
WHERE PostalCode = 98027

Select records that are only associated with a record in another table

Not sure if the title explains this scenario in full, so I will be as descriptive as I can. I'm using a SQL Server database and have the following 4 tables:
CUSTOMERS:
CustomerID CustomerName
--------------------------
100001 Mr J Bloggs
100002 Mr J Smith
POLICIES:
PolicyID PolicyTypeID CustomerID
-----------------------------------
100001 100001 100001
100002 100002 100001
100003 100003 100001
100004 100001 100002
100005 100002 100002
POLICYTYPES:
PolicyTypeID PolTypeName ProviderID
-----------------------------------------
100001 ISA 100001
100002 Pension 100001
100003 ISA 100002
PROVIDERS:
ProviderID ProviderName
--------------------------
100001 ABC Ltd
100002 Bloggs Plc
This is obviously a stripped down version and the actual database contains a lot more records. What I am looking to do is return a list of clients who ONLY have products from a certain provider. So in the example above, if I want to return customers who have policies with ABC Ltd with this SQL:
SELECT
C.CustomerName, P.PolicyID, PT.PolTypeName, Providers.ProviderName
FROM
Customers C
LEFT JOIN
Policies P ON C.CustomerID = P.CustomerID
LEFT JOIN
PolicyTypes PT ON P.PolicyTypeID = PT.PolicyTypeID
LEFT JOIN
Providers PR ON PR.ProviderID = PT.ProviderID
WHERE
PR.ProviderID = 100001
It will currently return both customers in the Customers table. But the customer Mr J Bloggs actually holds policies provided by Bloggs Plc as well. I don't want this. I only want to return the customers who hold ONLY policies from ABC Ltd, so the SQL I need should only return Mr J Smith.
Hope I've been clear, if not please let me know.
Many thanks in advance
Steve
Dirty but readable:
SELECT C.CustomerName, P.PolicyID, PT.PolTypeName, Providers.ProviderName
FROM Customers C LEFT JOIN Policies P ON C.CustomerID = P.CustomerID
LEFT JOIN PolicyTypes PT ON P.PolicyTypeID = PT.PolicyTypeID
LEFT JOIN Providers PR ON PR.ProviderID = PT.ProviderID
WHERE PR.ProviderID = 100001 AND C.CustomerName NOT IN (
SELECT C.CustomerName
FROM Customers C LEFT JOIN Policies P ON C.CustomerID = P.CustomerID
LEFT JOIN PolicyTypes PT ON P.PolicyTypeID = PT.PolicyTypeID
LEFT JOIN Providers PR ON PR.ProviderID = PT.ProviderID
WHERE PR.ProviderID <> 100001
)
Tthe idea is that you additionally perform a NOT IN on customerid's that are linked to other providers:
SELECT C.CustomerName, P.PolicyID, PT.PolTypeName, Providers.ProviderName
FROM Customers C LEFT JOIN Policies P ON C.CustomerID = P.CustomerID
LEFT JOIN PolicyTypes PT ON P.PolicyTypeID = PT.PolicyTypeID
LEFT JOIN Providers PR ON PR.ProviderID = PT.ProviderID
WHERE PR.ProviderID = 100001
--NEW PART
AND C.CustomerID NOT IN
(
SELECT P.CustomerID
FROM Policies P
LEFT JOIN PolicyTypes PT ON P.PolicyTypeID = PT.PolicyTypeID
LEFT JOIN Providers PR ON PR.ProviderID = PT.ProviderID
WHERE PR.ProviderID <> 100001
)
try this one...
SELECT C.CustomerName, P.PolicyID, PT.PolTypeName, Providers.ProviderName
from Customers C inner join POLICIES P ON C.CustomerID = P.CustomerID
inner join PT ON P.PolicyTypeID = PT.PolicyTypeID
inner join Providers PR ON PR.ProviderID = PT.ProviderID
where PR.ProviderID = 100001 and c.CustomerID not in
(SELECT C.CustomerID from Customers C
inner join POLICIES P ON C.CustomerID = P.CustomerID
inner join PT ON P.PolicyTypeID = PT.PolicyTypeID
inner join Providers PR ON PR.ProviderID = PT.ProviderID where PR.ProviderID <> 100001)