Volume of store sql - sql

i want the top 10 stores with the highest volume(percentage) of sales and the 5 with the lowest volume(percentage) of sales in a single report. Here's what i have done until now
SELECT TOP 10 Stores.Store_ID,Suppliers$.NAME,SUM(Store.QTY*Product.PRICE) AS StoreSales
FROM Stores
INNER JOIN Invoices$ ON Stores.store_ID=Invoices.Store_ID
INNER JOIN InvDetails ON Invoices.INVOICE_ID=InvDetails.INVOICE_ID
INNER JOIN Products ON Products.PRODUCT_ID=InvDetails.PRODUCT_ID
GROUP BY Stores.Store_ID,Stores.NAME
ORDER BY StoresSales DESC

select TOP 10 ...
from ...
group by ...
order by StoresSales DESC
union
select TOP 5 ...
from ...
group by ...
order by StoresSales ASC

You can do this with a CTE by dividing the query in two, the first part extracts the highest and the second part the lowest
With c as(
SELECT TOP 10 Stores.Store_ID,Suppliers$.NAME,SUM(Store.QTY*Product.PRICE) AS StoreSales
,cat = 'Max'
FROM Stores
INNER JOIN Invoices$ ON Stores.store_ID=Invoices.Store_ID
INNER JOIN InvDetails ON Invoices.INVOICE_ID=InvDetails.INVOICE_ID
INNER JOIN Products ON Products.PRODUCT_ID=InvDetails.PRODUCT_ID
GROUP BY Stores.Store_ID,Stores.NAME
ORDER BY StoresSales DESC
),
d as (
SELECT TOP 5 Stores.Store_ID,Suppliers$.NAME,SUM(Store.QTY*Product.PRICE) AS StoreSales
,cat = 'Min'
FROM Stores
INNER JOIN Invoices$ ON Stores.store_ID=Invoices.Store_ID
INNER JOIN InvDetails ON Invoices.INVOICE_ID=InvDetails.INVOICE_ID
INNER JOIN Products ON Products.PRODUCT_ID=InvDetails.PRODUCT_ID
GROUP BY Stores.Store_ID,Stores.NAME
ORDER BY StoresSales asc
)
Select *
From c
Union all
Select *
From d

You can use ROW_NUMBER() :
SELECT Stores.Store_ID, Suppliers$.NAME, SUM(Store.QTY*Product.PRICE) AS StoreSales,
ROW_NUMBER() OVER (PARTITION BY Stores.Store_ID, Suppliers$.NAME ORDER BY SUM(Store.QTY*Product.PRICE) DESC) AS MAX_SEQ,
ROW_NUMBER() OVER (PARTITION BY Stores.Store_ID, Suppliers$.NAME ORDER BY SUM(Store.QTY*Product.PRICE)) AS MIN_SEQ
FROM Stores INNER JOIN
Invoices$
ON Stores.store_ID = Invoices.Store_ID INNER JOIN
InvDetails
ON Invoices.INVOICE_ID = InvDetails.INVOICE_ID INNER JOIN
Products
ON Products.PRODUCT_ID = InvDetails.PRODUCT_ID
GROUP BY Stores.Store_ID, Suppliers$.NAME;
By using this, you can filter out :
SELECT t.*
FROM ( <query here>
) t
WHERE (t.MAX_SEQ <= 10 OR MIN_SEQ <= 5);

You could union your query with basically the same query, but change it to top 5 and in ascending order:
SELECT TOP 10 Stores.Store_ID,Suppliers$.NAME,SUM(Store.QTY*Product.PRICE) AS
StoreSales
FROM Stores
INNER JOIN Invoices$ ON Stores.store_ID=Invoices.Store_ID
INNER JOIN InvDetails ON Invoices.INVOICE_ID=InvDetails.INVOICE_ID
INNER JOIN Products ON Products.PRODUCT_ID=InvDetails.PRODUCT_ID
GROUP BY Stores.Store_ID,Stores.NAME
ORDER BY StoresSales DESC
UNION
SELECT TOP 5 Stores.Store_ID,Suppliers$.NAME,SUM(Store.QTY*Product.PRICE) AS
StoreSales
FROM Stores
INNER JOIN Invoices$ ON Stores.store_ID=Invoices.Store_ID
INNER JOIN InvDetails ON Invoices.INVOICE_ID=InvDetails.INVOICE_ID
INNER JOIN Products ON Products.PRODUCT_ID=InvDetails.PRODUCT_ID
GROUP BY Stores.Store_ID,Stores.NAME
ORDER BY StoresSales ASC

Related

Find the nth highest

SELECT CONCAT(C.CUSTOMER_FNAME, ' ',C.CUSTOMER_LNAME) AS FullNAME, SUM(QTY* PRICE)AS TOTAL_SPENDINGS
FROM (SELECT DISTINCT TOP 2 TOTAL_SPENDINGS) RESULT
Customers$ C INNER JOIN Invoices$ Inv ON C.CUSTOMER_ID=Inv.CUSTOMER_ID
INNER JOIN InvDetails$ InvD ON Inv.INVOICE_ID=InvD.INVOICE_ID
INNER JOIN Products$ P ON P.PRODUCT_ID=InvD.PRODUCT_ID
GROUP BY C.CUSTOMER_FNAME,C.CUSTOMER_LNAME
ORDER BY TOTAL_SPENDINGS DESC
I am trying to prin the k-highest spending customers this is what i have done until now but i get
Incorrect syntax near 'Customers$'.
You are missing the join condition between the calculated table RESULT and the Customers table:
SELECT CONCAT(C.CUSTOMER_FNAME, ' ',C.CUSTOMER_LNAME) AS FullNAME, SUM(QTY* PRICE)AS TOTAL_SPENDINGS
FROM (SELECT DISTINCT TOP 2 TOTAL_SPENDINGS) RESULT
<missing INNER / LEFT join here>
Customers$ C <missing ON here> INNER JOIN Invoices$ Inv ON C.CUSTOMER_ID=Inv.CUSTOMER_ID
INNER JOIN InvDetails$ InvD ON Inv.INVOICE_ID=InvD.INVOICE_ID
INNER JOIN Products$ P ON P.PRODUCT_ID=InvD.PRODUCT_ID
GROUP BY C.CUSTOMER_FNAME,C.CUSTOMER_LNAME
ORDER BY TOTAL_SPENDINGS DESC

Select a name in sql

I selecting the category name from a category table using the below query
select Category.Name
from Product
inner join ProductCategory on ProductCategory.PID=Product.PID
inner join ProductMaterial on ProductMaterial.PID=Product.PID
left join Category on Category.NodeId=ProductCategory.CID
where PID in('2233','4432','5665','1252')
group by ProductCategory.CID, ProductMaterial.MID,Category.DanishName
the query is working the result of this query is
Electronics
Electronics
Electronics
Home and Garden
I want only select most number of category name, here I need only Electronics.How to get this.Thanks in advance for help...>>
Try this:
MySQL
SELECT A.name, COUNT(A.name) nameCnt
FROM (SELECT C.Name
FROM Product P
INNER JOIN ProductCategory PC ON PC.PID=P.PID
INNER JOIN ProductMaterial PM ON PM.PID=P.PID
INNER JOIN Category C ON C.NodeId=PC.CID
WHERE PID IN('2233','4432','5665','1252')
GROUP BY PC.CID, PM.MID, C.DanishName
) AS A
GROUP BY A.name
ORDER BY nameCnt DESC LIMIT 1;
SQL Server
SELECT TOP 1 A.name, COUNT(A.name) nameCnt
FROM (SELECT C.Name
FROM Product P
INNER JOIN ProductCategory PC ON PC.PID=P.PID
INNER JOIN ProductMaterial PM ON PM.PID=P.PID
INNER JOIN Category C ON C.NodeId=PC.CID
WHERE PID IN('2233','4432','5665','1252')
GROUP BY PC.CID, PM.MID, C.DanishName
) AS A
GROUP BY A.name
ORDER BY nameCnt DESC;

SELECT DISTINCT TOP 5 in SQL Server

I can't get this sql query right...
I want the top 5 latest comments from tblComment. The problem is that I get more then one comment with the same ProductID. I don't want that.
SELECT DISTINCT TOP 5
tblProduct.ProductID,
tblProduct.ProductName,
tblComment.DateAdded
FROM
tblComment
INNER JOIN
tblProduct ON tblProduct.ProductID = tblComment.ProductID
ORDER BY
tblComment.DateAdded DESC
What am I doing wrong?
Assuming your comment table has an id field try this:
SELECT TOP 5
tblProduct.ProductID,
tblProduct.ProductName,
tblComment.DateAdded
FROM tblComment
JOIN tblProduct ON tblProduct.ProductID = tblComment.ProductID
JOIN (Select ProductID, max(id) as maxid From tblComment Group By ProductId) t on tblComment.id = t.maxid
ORDER BY tblComment.DateAdded DESC
You would have to sub select - use the following example to suit your needs.
SELECT TOP 5 tblProduct.ProductID,
tblProduct.ProductName,
tblComment.DateAdded
FROM tblComment INNER JOIN
tblProduct ON tblProduct.ProductID = tblComment.ProductID
and tblProduct.ProductID
IN (
SELECT tblProduct.ProductID
FROM tblComment
INNER JOIN tblProduct ON tblProduct.ProductID = tblComment.ProductID
GROUP BY tblProduct.ProductID
HAVING count( tblProduct.ProductID ) =1
)
Products ranked by time of latest comment.
This approach uses a CTE and and a rank function. This query is small but on larger queries these functions can make things more organized and readable.
with lastComment as (
select c.productID, max(DateAdded) DateAdded,
row_number() over(order by max(dateAdded)) rank
from tblComment c
group by c.productID
)
SELECT
tblProduct.ProductID,
tblProduct.ProductName,
tblComment.DateAdded
FROM
tblProduct
join lastComment ON tblProduct.ProductID = lastCommnet.ProductID
WHERE
lastComment.rank >= 5
ORDER BY lastComment.rank

How to have SQL INNER JOIN accept null results

I have the following query:
SELECT TOP 25 CLIENT_ID_MD5, COUNT(CLIENT_ID_MD5) TOTAL
FROM dbo.amazonlogs
GROUP BY CLIENT_ID_MD5
ORDER BY COUNT(*) DESC;
Which returns:
283fe255cbc25c804eb0c05f84ee5d52 864458
879100cf8aa8b993a8c53f0137a3a176 126122
06c181de7f35ee039fec84579e82883d 88719
69ffb6c6fd5f52de0d5535ce56286671 68863
703441aa63c0ac1f39fe9e4a4cc8239a 47434
3fd023e7b2047e78c6742e2fc5b66fce 45350
a8b72ca65ba2440e8e4028a832ec2160 39524
...
I want to retrieve the corresponding client name (FIRM) using the returned MD5 from this query, so a row might look like:
879100cf8aa8b993a8c53f0137a3a176 126122 Burger King
So I made this query:
SELECT a.CLIENT_ID_MD5, COUNT(a.CLIENT_ID_MD5) TOTAL, c.FIRM
FROM dbo.amazonlogs a
INNER JOIN dbo.customers c
ON c.CLIENT_ID_MD5 = a.CLIENT_ID_MD5
GROUP BY a.CLIENT_ID_MD5, c.FIRM
ORDER BY COUNT(*) DESC;
This returns something like:
879100cf8aa8b993a8c53f0137a3a176 126122 Burger King
06c181de7f35ee039fec84579e82883d 88719 McDonalds
703441aa63c0ac1f39fe9e4a4cc8239a 47434 Wendy's
3fd023e7b2047e78c6742e2fc5b66fce 45350 Tim Horton's
Which works, except I need to return an empty value for c.FIRM if there is no corresponding FIRM for a given MD5. For example:
879100cf8aa8b993a8c53f0137a3a176 126122 Burger King
06c181de7f35ee039fec84579e82883d 88719 McDonalds
69ffb6c6fd5f52de0d5535ce56286671 68863
703441aa63c0ac1f39fe9e4a4cc8239a 47434 Wendy's
3fd023e7b2047e78c6742e2fc5b66fce 45350 Tim Horton's
How should I modify the query to still return a row even if there is no corresponding c.FIRM?
Replace INNER JOIN with LEFT JOIN
use LEFT JOIN instead of INNER JOIN
Instead of doing an INNER join, you should do a LEFT OUTER join:
SELECT
a.CLIENT_ID_MD5,
COUNT(a.CLIENT_ID_MD5) TOTAL,
ISNULL(c.FIRM,'')
FROM
dbo.amazonlogs a LEFT OUTER JOIN
dbo.customers c ON c.CLIENT_ID_MD5 = a.CLIENT_ID_MD5
GROUP BY
a.CLIENT_ID_MD5,
c.FIRM
ORDER BY COUNT(0) DESC
http://www.w3schools.com/sql/sql_join.asp
An inner join excludes NULLs; you want a LEFT OUTER join.
SELECT a.CLIENT_ID_MD5, COUNT(a.CLIENT_ID_MD5) TOTAL, IsNull(c.FIRM, 'Unknown') as Firm
FROM dbo.amazonlogs a
LEFT JOIN dbo.customers c ON c.CLIENT_ID_MD5 = a.CLIENT_ID_MD5
GROUP BY a.CLIENT_ID_MD5, c.FIRM ORDER BY COUNT(*) DESC;
This will give you a value of "Unknown" when records in the customers table don't exist. You could obviously drop that part and just return c.FIRM if you want to have actual nulls instead.
Change your INNER JOIN to an OUTER JOIN...
SELECT a.CLIENT_ID_MD5, COUNT(a.CLIENT_ID_MD5) TOTAL, c.FIRM
FROM dbo.amazonlogs a
LEFT OUTER JOIN dbo.customers c
ON c.CLIENT_ID_MD5 = a.CLIENT_ID_MD5
GROUP BY a.CLIENT_ID_MD5, c.FIRM
ORDER BY COUNT(*) DESC;
WITH amazonlogs_Tallies
AS
(
SELECT a.CLIENT_ID_MD5, COUNT(a.CLIENT_ID_MD5) TOTAL
FROM dbo.amazonlogs a
GROUP
BY a.CLIENT_ID_MD5
),
amazonlogs_Tallies_Firms
AS
(
SELECT a.CLIENT_ID_MD5, a.TOTAL, c.FIRM
FROM amazonlogs_Tallies a
INNER JOIN dbo.customers c
ON c.CLIENT_ID_MD5 = a.CLIENT_ID_MD5
)
SELECT CLIENT_ID_MD5, TOTAL, FIRM
FROM amazonlogs_Tallies_Firms
UNION
SELECT CLIENT_ID_MD5, TOTAL, '{{NOT_KNOWN}}'
FROM amazonlogs_Tallies
EXCEPT
SELECT CLIENT_ID_MD5, TOTAL, '{{NOT_KNOWN}}'
FROM amazonlogs_Tallies_Firms;

SQL: improving join efficiency

If I turn this sub-query which selects sales persons and their highest price paid for any item they sell:
select *,
(select top 1 highestProductPrice
from orders o
where o.salespersonid = s.id
order by highestProductPrice desc ) as highestProductPrice
from salespersons s
in to this join in order to improve efficiency:
select *, highestProductPrice
from salespersons s join (
select salespersonid, highestProductPrice, row_number(
partition by salespersonid
order by salespersonid, highestProductPrice) as rank
from orders ) o on s.id = o.salespersonid
It still touches every order record (it enumerates the entire table before filtering by salespersonid it seems.) However you cannot do this:
select *, highestProductPrice
from salespersons s join (
select salespersonid, highestProductPrice, row_number(
partition by salespersonid
order by salespersonid, highestProductPrice) as rank
from orders
where orders.salepersonid = s.id) o on s.id = o.salespersonid
The where clause in the join causes a `multi-part identifier "s.id" could not be bound.
Is there any way to join the top 1 out of each order group with a join but without touching each record in orders?
Try
SELECT
S.*,
T.HighestProductPrice
FROM
SalesPersons S
CROSS APPLY
(
SELECT TOP 1 O.HighestProductPrice
FROM Orders O
WHERE O.SalesPersonid = S.Id
ORDER BY O.SalesPersonid, O.HighestProductPrice DESC
) T
would
select s.*, max(highestProductPrice)
from salespersons s
join orders o on o.salespersonid = s.id
group by s.*
or
select s.*, highestProductPrice
from salespersons s join (select salepersonid,
max(highestProductPrice) as highestProductPrice
from orders o) as o on o.salespersonid = s.id
work?