Multiple joins from multiple tables - sql

I'm using SQL Server and I'm having a difficult time trying to get the results from a SELECT query.
I have 6 tables:
Product
Market
Seller
Buyer
Customer (data about customers - buyers and sellers)
Currency
select * from Product;
id(PK) | name_product
-------+--------------
1 | apple
2 | orange
3 | juice
select * from Market;
OrderID(PK) |SellOrderID(FK) | BuyOrderID(FK) | product-id
--------------+----------------+----------------+-----------
45 | 5 | 15 | 1
46 | 3 | 36 | 3
58 | 4 | 8 | 2
select * from Seller;
SellOrderID |id_seller(PK) | id_product
--------------+--------------+---------------------
5 | 5 | 1
3 | 3 | 3
4 | 2 | 2
select * from Buyer;
BuyOrderID |id_Buyer(PK) | id_product
--------------+--------------+---------------------
15 | 1 | 1
36 | 4 | 3
8 | 6 | 2
select * from Customer;
id_customer(PK) | name_customer
----------------+---------------
1 | Alice
2 | Sam
3 | Katy
4 | Soul
5 | Fab
6 | Yas
select * from Currency;
id_product(PK,FK) | currency(PK)
------------------*-------------
1 | EUR
2 | USD
3 | EUR
I'm looking to select the name of customers, their orders, the name of product bought and sold and the currency given to each product.
But I am not getting correct result. I want results as shown below:
name_customer | OrderID | name_product | currency(PK)
---------------+----------+--------------+-------------
Alice | 45 | apple | EUR
Sam | 58 | juice | EUR
Katy | 46 | orange | USD
Soul | 46 | apple | EUR
Fab | 45 | juice | EUR
Yas | 58 | orange | USD
Please advise

SELECT c.name_customer
,m.OrderID
,p.name_product
,cc.currency
FROM Customer c
INNER JOIN Buyer b ON b.id_Buyer = c.id_customer
INNER JOIN Market m ON m.BuyOrderID = b.BuyOrderID
INNER JOIN Product p ON p.id = m.product-id
INNER JOIN Currency cc ON cc.id_product = p.id
Hopefully it should work! If not please let me know.

Related

SUB TOTAL WITH MULTIPLE TABLE

I want to show the subtotals of each product name and maybe the commands I made are useless,
is there any suggestions for me
I have 3 tables
select
ORDERS.ORDER_NUM,
PRODUCT.PRODUCT_ID,
PRODUCT.PRODUCT_NAME,
ORDER_DETAILS.QUANTITY,
ORDER_DETAILS.UNIT_PRICE,
sum(ORDER_DETAILS.UNIT_PRICE) as SUBTOTAL
from
ORDER_DETAILS
inner join ORDERS on ORDER_DETAILS.ORDER_NUM = ORDERS.ORDER_NUM
inner join PRODUCT on ORDER_DETAILS.PRODUCT_ID = PRODUCT.PRODUCT_ID
group by
ORDER_DETAILS.ITEM_NUM
order by
PRODUCT.PRODUCT_NAME;
+-----------+------------+--------------+----------+------------+----------+
| ORDER_NUM | PRODUCT_ID | PRODUCT_NAME | QUANTITY | UNIT_PRICE | SUBTOTAL |
+-----------+------------+--------------+----------+------------+----------+
| 3004 | 2001 | BEER | 10 | 160,000 | 160 |
| 3012 | 2001 | BEER | 5 | 160,000 | 160 |
| 3002 | 2005 | CAKE | 5 | 50,000 | 50 |
| 3001 | 2004 | CIGARETTE | 2 | 25,000 | 25 |
| 3011 | 2004 | CIGARETTE | 5 | 25,000 | 25 |
| 3005 | 2007 | ICE CREAM | 50 | 10,000 | 10 |
| 3007 | 2010 | MILK | 3 | 45,000 | 45 |
| 3010 | 2010 | MILK | 7 | 12,000 | 12 |
| 3008 | 2008 | NOODLES | 1 | 5,000 | 5 |
| 3013 | 2006 | SODA | 50 | 12,000 | 12 |
| 3009 | 2002 | WINE | 1 | 200,000 | 200 |
| 3003 | 2002 | WINE | 2 | 200,000 | 200 |
| 3006 | 2002 | WINE | 1 | 200,000 | 200 |
+-----------+------------+--------------+----------+------------+----------+
You don't specify the database. However, you need to fix your query:
Details from the order and order line are not appropriate, if you are summarizing by product.
The SELECT and GROUP BY lists should be consistent.
The total you want is probably the price times the quantity.
So, the query should be more like this:
select p.PRODUCT_ID, p.PRODUCT_NAME,
sum(od.UNIT_PRICE * od.QUANTITY) as SUBTOTAL
from ORDER_DETAILS od join
ORDERS o
on od.ORDER_NUM = o.ORDER_NUM join
PRODUCT p
on od.PRODUCT_ID = p.PRODUCT_ID
group by p.PRODUCT_ID, p.PRODUCT_NAME
order by p.PRODUCT_NAME;
Also note the use of table aliases, so the query is easier to write and to read.

SQL Group By and sum of other column

following is raw table
+--------------+---------------+----------+---------+-----------+
| CustomerName | InvoiceNumber | ItemRate | TaxRate | TaxAmount |
+--------------+---------------+----------+---------+-----------+
| A | 1 | 500 | 4% | 20 |
| B | 2 | 300 | 9% | 27 |
| B | 2 | 100 | 9% | 9 |
| B | 2 | 400 | 4% | 16 |
| C | 3 | 250 | 9% | 22.5 |
| C | 3 | 650 | 4% | 26 |
| D | 4 | 200 | 4% | 8 |
| D | 4 | 100 | 4% | 4 |
+--------------+---------------+----------+---------+-----------+
I want output like this:
+--------------+---------------+--------------+---------+-----------+
| CustomerName | InvoiceNumber | InvoiceTotal | TaxRate | TaxAmount |
+--------------+---------------+--------------+---------+-----------+
| A | 1 | 500 | 4% | 20 |
| B | 2 | 800 | 9% | 36 |
| B | 2 | 800 | 4% | 16 |
| C | 3 | 900 | 9% | 22.5 |
| C | 3 | 900 | 4% | 26 |
| D | 4 | 300 | 4% | 12 |
+--------------+---------------+--------------+---------+-----------+
I am having issue with sum of Invoice value when doing Group By.
I have to do group by with "TaxRate" to combine similar Taxes and along with it i want to include new column in result which shows Total for that perticular Invoice.
Invoice Total column should have sum of entire invoice, where as my current query is summing Total by tax group and not by entire invoice.
my query is:
Select CustomerName, InvoiceNumber, sum(itemrate) as InvoiceTotal, TaxRate, sum(TaxAmount)
from salestable group by customername,invoicenumber, Taxrate
Please help to resolve this.
Thanks
If I understand correctly, you want to sum itemrate over the invoice for each customer:
select CustomerName, InvoiceNumber,
sum(sum(itemrate)) over (partition by CustomerName, InvoiceNumber) as InvoiceTotal,
TaxRate,
sum(TaxAmount) as TaxAmount
from salestable
group by customername, invoicenumber, Taxrate
Try this-
WITH CTE AS
(
SELECT CustomerName,SUM(ItemRate) InvoiceTotal
FROM your_table
GROUP BY CustomerName
)
SELECT A.CustomerName,A.InvoiceNumber,B.InvoiceTotal,A.TaxRate,SUM(A.TaxAmount)
FROM your_table A
LEFT JOIN CTE B ON A.CustomerName = B.CustomerName
GROUP BY A.CustomerName,A.InvoiceNumber,B.InvoiceTotal,A.TaxRate
ORDER BY A.CustomerName,A.TaxRate DESC
Something like:
SELECT tab.CustomerName,
tab.InvoiceNumber,
it.InvoiceTotal,
tab.TaxRate,
SUM(tab.TaxAmount) AS TaxAmount
FROM tab
INNER JOIN (
SELECT InvoiceNumber, SUM(ItemRate) AS InvoiceTotal FROM tab GROUP BY InvoiceNumber
) it ON it.InvoiceNumber = tab.InvoiceNumber
GROUP BY tab.CustomerName, tab.InvoiceNumber, it.InvoiceTotal, tab.TaxRate
ORDER BY tab.CustomerName, tab.TaxRate DESC
See the associated fiddle.
Results:
A 1 500 4 20
B 2 800 9 36
B 2 800 4 16
C 3 900 9 22.5
C 3 900 4 26
D 4 300 4 12

Using CTE to count number of rows in inner query

I'm learning CTE and I've encounter an exercise on I cannot solve. It is not a homework, but an exercise from an online course I've taken to learn SQL. I'm interested in where I've made a mistake and some explanation so answering with only the correct code will not help me to learn CTE.
The task is to count projects that raised 100% to 150% of the minimum amount, and those that raised more than 150%.
I've written the following CTE:
WITH nice_proj AS
(SELECT project_id AS pid,
amount AS amount,
minimal_amount AS minimal
FROM donation d
INNER JOIN project p ON (d.project_id = p.id)
GROUP BY pid,
minimal,
amount
HAVING sum(amount) >= minimal_amount)
SELECT count(*) AS COUNT,
(CASE
WHEN sum(amount)/minimal <=1.5 THEN 'good projects'
ELSE 'great projects'
END) AS tag
FROM nice_proj
GROUP BY minimal;
The query returns nothing but it should produce something similar to:
+-------+----------------+
| count | tag |
+-------+----------------+
| 16 | good projects |
+-------+----------------+
| 7 | great projects |
+-------+----------------+
Please have a look at the tables (they are truncated):
donation
+----+------------+--------------+---------+------------+------------+
| id | project_id | supporter_id | amount | amount_eur | donated |
+----+------------+--------------+---------+------------+------------+
| 1 | 4 | 4 | 928.40 | 807.70 | 2016-09-07 |
+----+------------+--------------+---------+------------+------------+
| 2 | 8 | 18 | 384.38 | 334.41 | 2016-12-16 |
+----+------------+--------------+---------+------------+------------+
| 3 | 6 | 12 | 367.21 | 319.47 | 2016-01-21 |
+----+------------+--------------+---------+------------+------------+
| 4 | 2 | 19 | 108.62 | 94.50 | 2016-12-29 |
+----+------------+--------------+---------+------------+------------+
| 5 | 10 | 20 | 842.58 | 733.05 | 2016-11-30 |
+----+------------+--------------+---------+------------+------------+
| 6 | 4 | 15 | 653.76 | 568.77 | 2016-08-05 |
+----+------------+--------------+---------+------------+------------+
| 7 | 4 | 14 | 746.52 | 649.48 | 2016-08-03 |
+----+------------+--------------+---------+------------+------------+
| 8 | 10 | 3 | 962.36 | 837.25 | 2016-10-30 |
+----+------------+--------------+---------+------------+------------+
| 9 | 1 | 20 | 764.05 | 664.72 | 2016-08-24 |
+----+------------+--------------+---------+------------+------------+
| 10 | 10 | 4 | 1033.42 | 899.08 | 2016-02-26 |
+----+------------+--------------+---------+------------+------------+
| 11 | 5 | 6 | 571.90 | 497.55 | 2016-10-06 |
+----+------------+--------------+---------+------------+------------+
project
+----+------------+-----------+----------------+
| id | category | author_id | minimal_amount |
+----+------------+-----------+----------------+
| 1 | music | 1 | 1677 |
+----+------------+-----------+----------------+
| 2 | music | 5 | 21573 |
+----+------------+-----------+----------------+
| 3 | travelling | 2 | 4952 |
+----+------------+-----------+----------------+
| 4 | travelling | 5 | 3135 |
+----+------------+-----------+----------------+
| 5 | travelling | 2 | 8555 |
+----+------------+-----------+----------------+
| 6 | video | 4 | 6835 |
+----+------------+-----------+----------------+
| 7 | video | 4 | 7978 |
+----+------------+-----------+----------------+
| 8 | games | 1 | 4560 |
+----+------------+-----------+----------------+
| 9 | games | 2 | 4259 |
+----+------------+-----------+----------------+
| 10 | games | 1 | 5253 |
+----+------------+-----------+----------------+
My advice is to aggregate the donations table first, then compare it to the project table.
By doing this the join between donations and project is always 1:1. This in turn means you avoid having to group by "values" (minimal_amount), instead only grouping by "identifiers" (project_id).
WITH
donation_summary AS
(
SELECT
project_id,
SUM(amount) AS total_amount
FROM
donation
GROUP BY
project_id
)
SELECT
CASE WHEN d.total_amount <= p.minimal_amount * 1.5
THEN 'good projects'
ELSE 'great projects'
END
AS tag,
COUNT(*) AS project_count
FROM
donation_summary AS d
INNER JOIN
project AS p
ON p.id = d.project_id
WHERE
d.total_amount >= p.minimal_amount
GROUP BY
tag
That said, I'd normally use the following final query and get two columns rather than two rows...
SELECT
SUM(CASE WHEN d.total_amount <= p.minimal_amount * 1.5 THEN 1 ELSE 0 END) AS good_projects,
SUM(CASE WHEN d.total_amount > p.minimal_amount * 1.5 THEN 1 ELSE 0 END) AS great_projects
FROM
donation_summary AS d
INNER JOIN
project AS p
ON p.id = d.project_id
WHERE
d.total_amount >= p.minimal_amount
You need to remove amount from the grouping, this should return the expected result:
WITH nice_proj AS
(SELECT project_id AS pid,
sum(amount) AS amount,
minimal_amount AS minimal
FROM donation d
INNER JOIN project p ON (d.project_id = p.id)
GROUP BY pid,
minimal
HAVING sum(amount) >= minimal_amount)
SELECT count(*) AS COUNT,
(CASE
WHEN amount/minimal <=1.5 THEN 'good projects'
ELSE 'great projects'
END) AS tag
FROM nice_proj
GROUP BY tag;

MS Access SQL getting results from different tables and sorting by date

i hope my description will be enough. i tried to remove all non-significant fields.
i have 5 tables (Customer, Invoice, Items, Invoice_Item, Payment):
Customer fields and sample date are:
+----+------+
| ID | Name |
+----+------+
| 1 | John |
| 2 | Mary |
+----+------+
Invoice fields and sample date are:
+----+-----------+----------+------+
| ID | Date | Customer | Tax |
+----+-----------+----------+------+
| 1 | 1.1.2017 | 1 | 0.10 |
| 2 | 2.1.2017 | 2 | 0.10 |
| 3 | 3.1.2017 | 1 | 0.10 |
| 4 | 3.1.2017 | 2 | 0.10 |
| 5 | 8.1.2017 | 1 | 0.10 |
| 6 | 11.1.2017 | 1 | 0.10 |
| 7 | 12.1.2017 | 2 | 0.10 |
| 8 | 13.1.2017 | 1 | 0.10 |
+----+-----------+----------+------+
Item fields and sample data are:
+----+--------+
| ID | Name |
+----+--------+
| 1 | Door |
| 2 | Window |
| 3 | Table |
| 4 | Chair |
+----+--------+
Invoice_Item fields and sample data are:
+------------+---------+--------+------------+
| Invoice_ID | Item_ID | Amount | Unit_Price |
+------------+---------+--------+------------+
| 1 | 1 | 4 | 10 |
| 1 | 2 | 2 | 20 |
| 1 | 3 | 1 | 30 |
| 1 | 4 | 2 | 40 |
| 2 | 1 | 1 | 10 |
| 2 | 3 | 1 | 15 |
| 2 | 4 | 2 | 12 |
| 3 | 3 | 4 | 15 |
| 4 | 1 | 1 | 10 |
| 4 | 2 | 20 | 30 |
| 4 | 3 | 15 | 30 |
| 5 | 1 | 4 | 10 |
| 5 | 2 | 2 | 20 |
| 5 | 3 | 1 | 30 |
| 5 | 4 | 2 | 40 |
| 6 | 1 | 1 | 10 |
| 6 | 3 | 1 | 15 |
| 6 | 4 | 2 | 12 |
| 7 | 3 | 4 | 15 |
| 8 | 1 | 1 | 10 |
| 8 | 2 | 20 | 30 |
| 8 | 3 | 15 | 30 |
+------------+---------+--------+------------+
The reason the price is in this table not in the item table is because it is customer specific price.
Payment fields are:
+----------+--------+-----------+
| Customer | Amount | Date |
+----------+--------+-----------+
| 1 | 40 | 3.1.2017 |
| 2 | 10 | 7.1.2017 |
| 1 | 60 | 10.1.2017 |
+----------+--------+-----------+
so my report should be combine all tables and sort by DATE (either from Invoice or Payment) for a certain customer.
so for e.g. for customer John (1) it should be like:
+------------+----------------+---------+-----------+
| Invoice_ID | Invoice_Amount | Payment | Date |
+------------+----------------+---------+-----------+
| 1 | 171 | - | 1.1.2017 |
| 3 | 54 | - | 3.1.2017 |
| - | - | 40 | 3.1.2017 |
| 5 | 171 | - | 8.1.2017 |
| - | 10 | 60 | 10.1.2017 |
| 6 | 44.1 | - | 11.1.2017 |
| 8 | 954 | - | 13.1.2017 |
+------------+----------------+---------+-----------+
it is sorted by date, Invoice amount is (sum of (Amount* unit price)) * (1-tax)
i started with union but then got lost.
here is my try:
SELECT Inv_ID as Num, SUM(Invoice_Items.II_Price*Invoice_Items.II_Amount) AS Amount, Inv_Date as Created
FROM Invoice INNER JOIN Invoice_Items ON Invoice.Inv_ID = Invoice_Items.II_Inv_ID
UNION ALL
SELECT Null as Num, P_Value as Amount, P_Date as Created
FROM Payments
ORDER BY created ASC
Your help is appreciated!
Thanks
You can generate the report you requested using the following SQL script:
SELECT CustomerID,Invoice_ID,Invoice_Amount,Payment,Date
FROM (
SELECT c.ID AS CustomerID, i.ID AS Invoice_ID, SUM((t.Amount * t.UnitPrice)*(1-i.tax)) AS Invoice_Amount, NULL AS Payment,i.Date
FROM (Customer c
LEFT JOIN Invoice i
ON c.ID = i.Customer)
LEFT JOIN Invoice_Item t
ON i.ID = t.Invoice_ID
GROUP BY c.ID, i.ID,i.Date
UNION
SELECT c.ID AS CustomerID,NULL AS Invoice_ID, NULL AS Invoice_Amount, p.Amount AS Payment, p.Date
FROM Customer c
INNER JOIN Payment p
ON c.ID = p.Customer ) a
ORDER BY CustomerID, Date, Payment ASC
Note: I've added CustomerID to the output so you know what customer the data corresponds to.
here is the Answer which worked for me, a bit corrected from #Catzeye Answer , which didnt show the second part of the Union.
SELECT c.ID AS CustomerID,NULL AS Invoice_ID, NULL AS Invoice_Amount, p.Amount AS Payment, p.Date
FROM Customer c
INNER JOIN Payment p
ON c.ID = p.Customer
UNION ALL
SELECT c.ID AS CustomerID, i.ID AS Invoice_ID, SUM((t.Amount * t.Unit_Price)*(1-i.tax)) AS Invoice_Amount, NULL AS Payment,i.Date
FROM (Customer c
INNER JOIN Invoice i
ON c.ID = i.Customer)
INNER JOIN Invoice_Item t
ON i.ID = t.Invoice_ID
GROUP BY c.ID, i.ID,i.Date
ORDER BY CustomerID, Date, Payment;

SQL Join Help - Sum and Apply Filter to Tables Before Join

I have a Stock View (that lists all the individual pieces of stock and the stock date) and a Sales View (that lists all of the sales and the date the sale occurred).
Stock View:
+----+------+-----+------------+
| ID | Item | Qty | Date |
+----+------+-----+------------+
| 1 | A | 3 | 01/01/2000 |
| 2 | A | 2 | 02/02/2000 |
| 3 | D | 9 | 05/06/2000 |
| 4 | F | 22 | 09/01/2001 |
| 5 | A | 10 | 01/04/2001 |
| 6 | C | 12 | 01/01/2002 |
+----+------+-----+------------+
Sales View:
+------+-----+------------+
| Item | Qty | Date |
+------+-----+------------+
| B | 3 | 01/01/2001 |
| B | 77 | 01/12/2001 |
| C | 9 | 02/02/2002 |
| A | 10 | 03/03/2002 |
| G | 2 | 05/06/2002 |
| C | 3 | 09/10/2012 |
+------+-----+------------+
I want to join these tables..but before doing so:
Stock view needs to be filtered between 2 date parameters #StockFrom and #StockTo
Sales view needs to be filtered between 2 date parameters #SalesFrom and #SalesTo
Sales view then needs to be grouped by Item and have the Qty Summed (so the date field needs to be dropped although it is being filtered on) and then joined onto the Stock View on the Item field.
So in essence I want to see the Stock View as it is (but filtered on dates) with an extra column showing the sales that have occurred between 2 dates for that item.
Desired Output:
+----+------+-----+------------+-------+
| ID | Item | Qty | Date | Sales |
+----+------+-----+------------+-------+
| 1 | A | 3 | 01/01/2000 | 10 |
| 2 | A | 2 | 02/02/2000 | 10 |
| 3 | D | 9 | 05/06/2000 | 0 |
| 4 | F | 22 | 09/01/2001 | 0 |
| 5 | A | 10 | 01/04/2001 | 10 |
| 6 | C | 12 | 01/01/2002 | 12 |
+----+------+-----+------------+-------+
Thanks to any help in advance!
SELECT
Stock.*,
IFNULL(SUM(Sales.Qty),0) AS Sales
FROM Stock
LEFT JOIN Sales ON Stock.Item=Sales.Item
WHERE Stock.Date BETWEEN #StockFrom AND #StockTo
AND (
Sales.Date BETWEEN #SalesFrom AND #SalesTo
OR Sales.Date IS NULL
)
GROUP BY Stock.ID
This is for MySQL, as you didn't specify the diaclect. SQLfiddle
EDIT
SELECT
Stock.ID AS ID,
MIN(Stock.Item) AS Item,
MIN(Stock.Qty) AS Qty,
MIN(Stock.Date) AS Date,
CASE WHEN SUM(Sales.Qty) IS NULL THEN 0 ELSE SUM(Sales.Qty) END AS Sales
FROM Stock
LEFT JOIN Sales ON Stock.Item=Sales.Item
WHERE Stock.Date BETWEEN #StockFrom AND #StockTo
AND (
Sales.Date BETWEEN #SalesFrom AND #SalesTo
OR Sales.Date IS NULL
)
GROUP BY Stock.ID
works for MS SQL (SQLfiddle)
Please try below query for MS Sql Server:
SELECT DISTINCT
a.ID,
a.Item,
a.Qty,
a.Date,
ISNULL(SUM(b.Qty) OVER (PARTITION BY a.Item, a.[Date]), 0) Sales
FROM
StockView a LEFT JOIN SalesView b on a.Item=b.Item