how to join more then two table in postgresql? - sql

i am running following query
select
to_char(sale_order.date_order ,'DD-MM-YYYY') , sum(sale_order.amount_total) as amount
from
public.sale_order
where
sale_order.order_year = '2015' and
sale_order.order_month = 'April'
group by
to_char(sale_order.date_order ,'DD-MM-YYYY') order by to_char(sale_order.date_order ,'DD-MM-YYYY') asc
its giving correct output
to_char.. amount
"14-04-2015"; 1298.00
"15-04-2015"; 4294.00
"16-04-2015"; 1398.00
"17-04-2015"; 1927.00
"18-04-2015"; 3094.00
"19-04-2015"; 6988.00
"20-04-2015"; 6641.00
"21-04-2015"; 3045.00
but i am trying to enter a condition which have multiple table connection then it gives different amount value
select
to_char(sale_order.date_order ,'DD-MM-YYYY') , sum(sale_order.amount_total) as amount
from
public.sale_order ,
public.sale_order_line ,
public.product_product ,
public.product_template ,
public.product_category
where
sale_order_line.product_id = product_product.id AND
product_product.product_tmpl_id = product_template.id AND
product_template.categ_id = product_category.id AND
sale_order.id = sale_order_line.order_id AND
sale_order_line.product_id = product_product.id AND
product_product.product_tmpl_id = product_template.id AND
product_template.categ_id = product_category.id AND
product_category.name = 'Starchi' and
sale_order.order_year = '2015' and
sale_order.order_month = 'April'
group by to_char(sale_order.date_order ,'DD-MM-YYYY') order by to_char(sale_order.date_order ,'DD-MM-YYYY') asc
then it gives different output
to_char amount
"14-04-2015"; 1298.00
"15-04-2015"; 4294.00
"16-04-2015"; 1398.00
"17-04-2015"; 2805.00 //wrong output
"18-04-2015"; 6188.00 //wrong output
"19-04-2015"; 13976.00 //wrong output
"20-04-2015"; 19229.00 //wrong output
"21-04-2015"; 3045.00
what is the exact problem please anybody can tell ?
and how to solve it ?

You made a mistake in your WHERE clauses, as Gordon Linoff already commented, leading to duplicate rows being retrieved and then summed up to give wrong totals. Following wildplasser's advice in his comment, using the JOIN syntax is much cleaner and less error-prone. Your query would look like this:
SELECT to_char(o.date_order, 'DD-MM-YYYY') AS "date", sum(o.amount_total) AS amount
FROM public.sale_order o
JOIN public.sale_order_line l ON l.order_id = o.id
JOIN public.product_product pp ON pp.id = l.product_id
JOIN public.product_template pt ON pt.id = pp.product_tmpl_id
JOIN public.product_category pc ON pc.id = pt.categ_id
WHERE pc.name = 'Starchi'
AND o.order_year = '2015'
AND o.order_month = 'April'
GROUP BY o.date_order
ORDER BY o.date_order ASC

[USING #Patrick 's cleaned up code] Most probable cause is that an 1:N relation exists between orders and order_lines, causing the orders with multiple order_lines to be included in the sum() more than once.
SELECT to_char(o.date_order, 'DD-MM-YYYY') AS date_order
, sum(o.amount_total) AS amount
FROM public.sale_order o
WHERE EXISTS ( SELECT *
-- These tables probably have an N:1 relation
-- to public.sale_order
-- We don't have to sum them; just check existence.
FROM public.sale_order_line l
JOIN public.product_product pp ON pp.id = l.product_id
JOIN public.product_template pt ON pt.id = pp.product_tmpl_id
JOIN public.product_category pc ON pc.id = pt.categ_id
WHERE pc.name = 'Starchi'
AND l.order_id = o.id
)
AND o.order_year = '2015'
AND o.order_month = 'April'
GROUP BY o.date_order
ORDER BY o.date_order ASC
;

Related

SQL: How to get distinct values out of string_Agg() function?

The following code
SELECT
DISTINCT(p.ID) AS ID
, PIT.Code AS Code
, year(PT.Date) AS Year
FROM fact.PreT PT
INNER JOIN dim.ProdIType PIT
ON PIT.ProdITypeSKey = PT.ProdITypeSKey
INNER JOIN dim.Proudct P
ON P.ProductSKey = pt.ProductSKey
WHERE p.ID = '15'
GROUP BY p.ID, PIT.Code, PT.Year
returns the following:
I have reconfigured my script to add aggregate and group the codes by id and year, however duplicates are spotted. Code and output below:
SELECT
DISTINCT(p.ID) AS ID
, string_agg(PIT.Code, ',') AS Code
, year(PT.Date) AS Year
FROM fact.PreT PT
INNER JOIN dim.ProdIType PIT
ON PIT.ProdITypeSKey = PT.ProdITypeSKey
INNER JOIN dim.Proudct P
ON P.ProductSKey = pt.ProductSKey
WHERE p.ID = '15'
GROUP BY p.ID, PT.Year
Result:
Desired output - distinct and ordered code ascending:
Can someone explain why string_acc is duplicating codes? how should I tackle this issue?
You need to subquery it and group again. Note that DISTINCT is not a function, it acts over the whole resultset, and is the same as grouping by all column.
SELECT
ID
, string_agg(Code, ',') AS Code
, [Year]
FROM (
SELECT
p.ID
, PIT.Code AS Code
, year(PT.Date) AS Year
FROM fact.PreT PT
INNER JOIN dim.ProdIType PIT
ON PIT.ProdITypeSKey = PT.ProdITypeSKey
INNER JOIN dim.Proudct P
ON P.ProductSKey = pt.ProductSKey
WHERE p.ID = '15'
GROUP BY p.ID, year(PT.Date), PIT.Code
) p
GROUP BY p.ID, PT.Year;

Easy Left Join SQL Syntax

New to SQL and want to complete a LEFT JOIN.
I have two seperate tables with the below code:
SELECT
StockCode, SalesOrder, SUM(OrderQty)
FROM
dbo.IopSalesPerf
WHERE
dbo.IopSalesPerf.CustRequestDate BETWEEN '2017-07-01' AND '2017-07-31'
AND EntrySystemTime = 1
AND Warehouse = '01'
AND StockCode = '001013'
GROUP BY
StockCode,SalesOrder
ORDER BY
StockCode ASC
SELECT
SalesOrder, SUM(NetSalesValue), SUM(QtyInvoiced)
FROM
ArTrnDetail
GROUP BY
SalesOrder
I would like to LEFT JOIN the last table onto the first using SalesOrder as the joining column. Can anyone assist with the syntax?
Simpliest way would be:
SELECT * FROM
(
SELECT StockCode,SalesOrder,sum(OrderQty)
FROM dbo.IopSalesPerf
WHERE dbo.IopSalesPerf.CustRequestDate between '2017-07-01' and '2017-07-31'
and EntrySystemTime = 1 and Warehouse = '01' and StockCode = '001013'
GROUP BY StockCode,SalesOrder
Order BY StockCode ASc
) AS A
LEFT JOIN
(
SELECT SalesOrder,sum(NetSalesValue),sum(QtyInvoiced)
FROM ArTrnDetail
Group by SalesOrder
) AS B
ON A.SalesOrder = B.SalesOrder

How to merge Two queries into one and result in one row

SELECT lp.lead_bucket_no ,
case when p.product = 'S-400' then qty end as 'S400' ,
case when p.product = 'Dish Antenna' then qty end as 'DishAntenna'
FROM lead_products lp INNER JOIN products p ON p.product_id = lp.product_id WHERE type = 'stock' GROUP BY lead_bucket_no ORDER BY lp.lead_bucket_no
and
SELECT lp.lead_bucket_no ,
case when p.product = 'S-400' then qty end as 'S400' ,
case when p.product = 'Dish Antenna' then qty end as 'DishAntenna'
FROM lead_products lp INNER JOIN products p ON p.product_id = lp.product_id WHERE type = 'order' GROUP BY lead_bucket_no ORDER BY lp.lead_bucket_no
how to merge these both query and and got record in single row. only type are different in both queries.
enter image description here
I think you just want OR (or IN) in the WHERE clause:
SELECT lp.lead_bucket_no,
SUM(case when p.product = 'S-400' then qty end) as S400,
SUM(case when p.product = 'Dish Antenna' then qty end) as DishAntenna
FROM lead_products lp INNER JOIN
products p
ON p.product_id = lp.product_id
WHERE type IN ('stock', 'order')
GROUP BY lead_bucket_no
ORDER BY lp.lead_bucket_no;
You also need some sort of aggregation for the expressions that are not in the GROUP BY clause. You may also want to aggregate by TYPE. It is unclear what you want for the final output.

SQL Server 2008 : FROM clause syntax error

My code returns a syntax error on L42 (the from clause). I've looked and looked and to me, the syntax looks correct for the FROM.
The top part of the code creates a temp table 'subproducts'. Then I want to pull data from DB tables & pull relevant details from the new temp table.
Any ideas?
drop table ##subproducts;
SELECT
F1.[OrderNo]
,F1.[OrderSeqNo]
,F1.[OrderLineNo]
,sum(F1.[LineCost]) as LineCost
,sum(F1.[NetCost]) as NetCost
,sum(F1.[OrderNet]) as OrderNet
INTO
##subproducts
FROM
[UFPData].[dbo].[SalesStats] F1
WHERE
F1.MainProd = 'S'
GROUP BY
F1.OrderNo, F1.OrderSeqNo, F1.OrderLineNo;
SELECT *
FROM SalesStats F1
LEFT OUTER JOIN ##subproducts F2 ON F1.OrderNo = F2.OrderNo
AND F1.OrderSeqNo = F2.Orderseqno
AND F1.OrderLineNo = F2.OrderLineNo
WHERE YEAR(InvDate) = 2015
AND MONTH(InvDate) = 5
AND CustNo = 100382
AND MainProd = 'Y';
SELECT
ContractInfo.CONTRNO,
ContractInfo.CONTRDESC,
repcode,
RepName,
PriceAgreement,
ordercycle,
SalesStats.CustNo,
Customer.CustName,
SalesStats.InvDate,
SalesStats.InvoiceNo,
salesstats.ProdCode,
Price as ContractPrice,
subproduct.LineCost as LineCost,
subproduct.NetCost as NetCost,
subproduct.OrderNet as OrderNet,
contractinfo.NETCOST as BidPrice,
contractinfo.NETCOST* SUM(quantity) as BidCost,
FROM
UFPData.dbo.SalesStats
RIGHT OUTER JOIN
##subproducts ON UFPData.dbo.SalesStats.ProdCode = ##subproducts.ProdCode,
UFPData.dbo.SalesStats
LEFT OUTER JOIN
UFPData.dbo.Customer ON UFPData.dbo.SalesStats.CustNo = UFPData.dbo.Customer.CustNo, UFPData.dbo.SalesStats
LEFT OUTER JOIN
Pricing.dbo.InvManCen ON UFPData.dbo.SalesStats.ProdCode = Pricing.dbo.invmancen.UFPCODE, UFPData.dbo.SalesStats
RIGHT OUTER JOIN
UFPData.dbo.ContractInfo ON UFPData.dbo.Customer.CustNo = UFPData.dbo.ContractInfo.CUSTNO
AND UFPData.dbo.salesstats.prodcode = UFPData.dbo.contractinfo.prodcode,
WHERE
invdate BETWEEN '2015-05-01' and '2015-05-31'
AND TeamCode IN ('tm1','tm2','tm3')
AND ContractInfo.CONTRNO IN ('1500','1502','1503','1504','1505','1506','701','702','703','705','141',
'712', '713', '714', '715', '716', '717', '718', '719', '730', '731', '732') or CONTRNO between '3000' and '3049')
--and left(ordercycle,1) <> 'c'
GROUP BY
ContractInfo.CONTRNO,
repcode,
RepName,
SalesStats.CustNo,
Customer.CustName,
SalesStats.InvDate,
salesstats.ProdCode,
Price,
contractinfo.NETCOST,
SalesStats.InvoiceNo,
InvManCen.PS98,
ContractInfo.CONTRDESC,
ordercycle,
PriceAgreement,
case
when invdate > ('20' + LEFT(ENDDATE,2)+ '-'+ SUBSTRING(cast(ENDDATE as varchar(6)),3,2)+ '-'+ SUBSTRING(cast(ENDDATE as varchar(6)),5,2)) then 'Expired' else 'Live' end;
Many thanks in advance
This doesn't look right to me:
FROM
UFPData.dbo.SalesStats right outer join ##subproducts on UFPData.dbo.SalesStats.ProdCode = ##subproducts.ProdCode,
UFPData.dbo.SalesStats left outer join UFPData.dbo.Customer on UFPData.dbo.SalesStats.CustNo = UFPData.dbo.Customer.CustNo,
UFPData.dbo.SalesStats left outer join Pricing.dbo.InvManCen on UFPData.dbo.SalesStats.ProdCode = Pricing.dbo.invmancen.UFPCODE,
UFPData.dbo.SalesStats right outer join UFPData.dbo.ContractInfo on UFPData.dbo.Customer.CustNo = UFPData.dbo.ContractInfo.CUSTNO and UFPData.dbo.salesstats.prodcode = UFPData.dbo.contractinfo.prodcode,
Usually the format is something like this:
FROM
TableName
INNER JOIN SomeOtherTable...
INNER JOIN AnotherTable...
Note that the first table is mentioned once, not before every join. You also seem to have errant commas after each join, which isn't syntactically correct. I think you want this:
FROM
UFPData.dbo.SalesStats
right outer join ##subproducts on UFPData.dbo.SalesStats.ProdCode = ##subproducts.ProdCode
left outer join UFPData.dbo.Customer on UFPData.dbo.SalesStats.CustNo = UFPData.dbo.Customer.CustNo
left outer join Pricing.dbo.InvManCen on UFPData.dbo.SalesStats.ProdCode = Pricing.dbo.invmancen.UFPCODE
right outer join UFPData.dbo.ContractInfo on UFPData.dbo.Customer.CustNo = UFPData.dbo.ContractInfo.CUSTNO and UFPData.dbo.salesstats.prodcode = UFPData.dbo.contractinfo.prodcode
There could very well be more syntax errors throughout your query. I recommend formatting the code a little more cleanly to more easily find them. For example, contrast the above with something like this:
FROM
UFPData.dbo.SalesStats
RIGHT OUTER JOIN ##subproducts
ON UFPData.dbo.SalesStats.ProdCode = ##subproducts.ProdCode
LEFT OUTER JOIN UFPData.dbo.Customer
ON UFPData.dbo.SalesStats.CustNo = UFPData.dbo.Customer.CustNo
LEFT OUTER JOIN Pricing.dbo.InvManCen
ON UFPData.dbo.SalesStats.ProdCode = Pricing.dbo.invmancen.UFPCODE
RIGHT OUTER JOIN UFPData.dbo.ContractInfo
ON UFPData.dbo.Customer.CustNo = UFPData.dbo.ContractInfo.CUSTNO
AND UFPData.dbo.salesstats.prodcode = UFPData.dbo.contractinfo.prodcode
It's a small change, and often a matter of personal preference, but well formatted code brings about a number of advantages. Less horizontal scrolling makes it easier to see the relevant code in a single glance, line breaks for specific keywords and clauses makes it easier to spot errant commas, etc.
Here's what I think should be valid syntax for what you've provided, please try it and compare it to the original as there were multiple errors:
DROP TABLE ##subproducts;
SELECT F1.[OrderNo] ,
F1.[OrderSeqNo] ,
F1.[OrderLineNo] ,
SUM(F1.[LineCost]) AS LineCost ,
SUM(F1.[NetCost]) AS NetCost ,
SUM(F1.[OrderNet]) AS OrderNet
INTO ##subproducts
FROM [UFPData].[dbo].[SalesStats] F1
WHERE F1.MainProd = 'S'
GROUP BY F1.OrderNo ,
F1.OrderSeqNo ,
F1.OrderLineNo;
SELECT *
FROM SalesStats F1
LEFT OUTER JOIN ##subproducts F2 ON F1.OrderNo = F2.OrderNo
AND F1.OrderSeqNo = F2.Orderseqno
AND F1.OrderLineNo = F2.OrderLineNo
WHERE YEAR(InvDate) = 2015
AND MONTH(InvDate) = 5
AND CustNo = 100382
AND MainProd = 'Y';
SELECT ContractInfo.CONTRNO ,
ContractInfo.CONTRDESC ,
repcode ,
RepName ,
PriceAgreement ,
ordercycle ,
SalesStats.CustNo ,
Customer.CustName ,
SalesStats.InvDate ,
SalesStats.InvoiceNo ,
SalesStats.ProdCode ,
Price AS ContractPrice ,
subproduct.LineCost AS LineCost ,
subproduct.NetCost AS NetCost ,
subproduct.OrderNet AS OrderNet ,
ContractInfo.NetCost AS BidPrice ,
ContractInfo.NetCost * SUM(quantity) AS BidCost
FROM UFPData.dbo.SalesStats
RIGHT OUTER JOIN ##subproducts ON UFPData.dbo.SalesStats.ProdCode = ##subproducts.ProdCode
LEFT OUTER JOIN UFPData.dbo.Customer ON UFPData.dbo.SalesStats.CustNo = UFPData.dbo.Customer.CustNo
LEFT OUTER JOIN Pricing.dbo.InvManCen ON UFPData.dbo.SalesStats.ProdCode = Pricing.dbo.invmancen.UFPCODE
RIGHT OUTER JOIN UFPData.dbo.ContractInfo ON UFPData.dbo.Customer.CustNo = UFPData.dbo.ContractInfo.CUSTNO
AND UFPData.dbo.salesstats.prodcode = UFPData.dbo.contractinfo.prodcode
WHERE invdate BETWEEN '2015-05-01' AND '2015-05-31'
AND TeamCode IN ( 'tm1', 'tm2', 'tm3' )
AND (ContractInfo.CONTRNO IN ( '1500', '1502', '1503', '1504', '1505',
'1506', '701', '702', '703', '705',
'141', '712', '713', '714', '715', '716',
'717', '718', '719', '730', '731', '732' )
OR CONTRNO BETWEEN '3000' AND '3049')
GROUP BY ContractInfo.CONTRNO ,
repcode ,
RepName ,
SalesStats.CustNo ,
Customer.CustName ,
SalesStats.InvDate ,
SalesStats.ProdCode ,
Price ,
ContractInfo.NetCost ,
SalesStats.InvoiceNo ,
InvManCen.PS98 ,
ContractInfo.CONTRDESC ,
ordercycle ,
PriceAgreement ,
CASE WHEN invdate > ( '20' + LEFT(ENDDATE, 2) + '-'
+ SUBSTRING(CAST(ENDDATE AS VARCHAR(6)), 3, 2)
+ '-' + SUBSTRING(CAST(ENDDATE AS VARCHAR(6)), 5,
2) ) THEN 'Expired'
ELSE 'Live'
END;

Need help understanding SUM

I would like to see the results total the received column and only return the item id once with the total received. Can someone explain why this is not working and help me get to where I need to be?
EDIT - Id like the results to be
Item A - 65
Item B - 52
Item C - 150
instead of what I am getting currently:
Item A - 15
Item A - 20
Item A - 30
Item B - 10
Item B - 15
etc
THANKS!
select S.supplier_id,
s.supplier_name,
ph.po_no,
ph.order_date,
ph.location_id,
im.item_id,
im.item_desc,
invs.supplier_part_no,
sum( pl.qty_received) as received,
pl.unit_price
from po_line pl
inner join po_hdr ph on ph.po_no = pl.po_no
inner join supplier s on s.supplier_id = ph.supplier_id
inner join inv_mast im on im.inv_mast_uid = pl.inv_mast_uid
left join inventory_supplier invs on invs.supplier_id = s.supplier_id
and invs.inv_mast_uid = im.inv_mast_uid
where ph.order_date between '2014-01-01' and '2014-12-31'
and ph.supplier_id = '101315'
and ph.delete_flag != 'Y'
and ph.complete = 'y'
and pl.delete_flag != 'y'
and pl.cancel_flag != 'y'
and ph.cancel_flag != 'y'
Group by
pl.qty_received,
im.item_id,
S.supplier_id,
s.supplier_name,
ph.po_no,
ph.location_id,
im.item_desc,
invs.supplier_part_no,
pl.unit_price,
ph.order_date
order by item_id
The problem is that the aggregate is grouping on other, changing values that cause separation in your data.
select S.supplier_id, -- values are the same, but is this necessary in your result set; if this value changes, you would have the separation in your data
s.supplier_name, -- cannot see in your picture, but these are likely all the same
ph.po_no, -- values are different, is this necessary in your result set?
ph.order_date, -- values are different, again, is this necessary in your result set?
ph.location_id, -- values are the same, but is this necessary in your result set; if this value changes, you would have the separation in your data
im.item_id, -- the primary grouping factor
im.item_desc, -- the description of the primary grouping factor (should not change per record)
invs.supplier_part_no, -- values are the same, but is this necessary in your result set; if this value changes, you would have the separation in your data
sum( pl.qty_received) as received, -- the aggregate you are performing
pl.unit_price -- we cannot see this in your picture, but this could also be a changing value that could cause separation in your data, is it necessary in your result set?
from po_line pl
inner join po_hdr ph on ph.po_no = pl.po_no
inner join supplier s on s.supplier_id = ph.supplier_id
inner join inv_mast im on im.inv_mast_uid = pl.inv_mast_uid
left join inventory_supplier invs on invs.supplier_id = s.supplier_id
and invs.inv_mast_uid = im.inv_mast_uid
where ph.order_date between '2014-01-01' and '2014-12-31'
and ph.supplier_id = '101315'
and ph.delete_flag != 'Y'
and ph.complete = 'y'
and pl.delete_flag != 'y'
and pl.cancel_flag != 'y'
and ph.cancel_flag != 'y'
Group by -- the Group by clause should change with a change in the columns selected
pl.qty_received, -- the aggregate should also, likely, not be part of the group by clause
im.item_id,
S.supplier_id,
s.supplier_name,
ph.po_no,
ph.location_id,
im.item_desc,
invs.supplier_part_no,
pl.unit_price,
ph.order_date
order by item_id
-- an example of how this might look
select S.supplier_id,
MAX(s.supplier_name),
im.item_id,
MAX(im.item_desc),
sum( pl.qty_received) as received,
from po_line pl
inner join po_hdr ph on ph.po_no = pl.po_no
inner join supplier s on s.supplier_id = ph.supplier_id
inner join inv_mast im on im.inv_mast_uid = pl.inv_mast_uid
left join inventory_supplier invs on invs.supplier_id = s.supplier_id
and invs.inv_mast_uid = im.inv_mast_uid
where ph.order_date between '2014-01-01' and '2014-12-31'
and ph.supplier_id = '101315'
and ph.delete_flag != 'Y'
and ph.complete = 'y'
and pl.delete_flag != 'y'
and pl.cancel_flag != 'y'
and ph.cancel_flag != 'y'
Group by
S.supplier_id,
im.item_id
order by item_id