group by function with complicated SELECT - sql

Hi
I have this Statement that select a sum of quantity ans Amounts of products from a big DataBase
SELECT
(SELECT Name FROM AD_Org WHERE AD_Org_ID = 1000001
) AS Org,
(SELECT bp.Name FROM C_BPartner bp WHERE bp.C_BPARTNER_ID = 0
) AS Selected_Vendor,
(SELECT MAX(bp.Name)
FROM C_BPartner bp
WHERE EXISTS
(SELECT 1
FROM M_Product_PO po
WHERE bp.C_BPARTNER_ID =po.C_BPARTNER_ID
AND po.M_PRODUCT_ID = p.M_PRODUCT_ID
AND po.ISCURRENTVENDOR ='Y'
AND AD_Org_ID = 1000001
)
) AS Vendor,
p.Value AS Value_Product,
p.Name AS Name_Product,
COALESCE( SUM(ol.QTYORDERED) , 0) AS qty_bought ,
COALESCE( SUM(ol.LINENETAMT) , 0) AS Amount_bought ,
COALESCE( SUM(ol2.QTYORDERED) , 0) AS qty_sales ,
COALESCE( SUM(ol2.LINENETAMT) , 0) AS Amount_sales,
bomOffQtyOnHand(p.M_PRODUCT_ID,
(SELECT NVL(M_WAREHOUSE_ID,0) FROM AD_OrgInfo WHERE AD_Org_ID = 1000001
), NULL) AS STOCK,
(SELECT Name FROM M_PRODUCT_CATEGORY pc WHERE pc.M_PRODUCT_CATEGORY_ID =0
) AS Product_Category
FROM M_Product p
LEFT OUTER JOIN C_OrderLine ol
ON (p.m_product_id = ol.m_product_id)
INNER JOIN C_Order o
....
....
WHERE (p.M_PRODUCT_CATEGORY_ID =0
....
....
)
ORDER BY p.value,
p.Nam
this statement give me always group function error
ORA-00937: not a single-group group function
when i Put this lines to fix it it give another group by error
GROUP BY SUM(ol.QTYORDERED) ,
SUM(ol.LINENETAMT),
SUM(ol2.QTYORDERED),
SUM(ol2.LINENETAMT),
p.Value,
p.name
error
ORA-00934: group function is not allowed here
I think I must put All the selected items in the group by so how can I put this
(SELECT Name FROM AD_Org WHERE AD_Org_ID = 1000001
) AS Org,
or this
(SELECT MAX(bp.Name)
FROM C_BPartner bp
WHERE EXISTS
(SELECT 1
FROM M_Product_PO po
WHERE
....
AND AD_Org_ID = 1000001
)
) AS Vendor,
in the group by or any other method to fix this error

You aggregate with SUM here:
COALESCE( SUM(ol.QTYORDERED) , 0) AS qty_bought ,
COALESCE( SUM(ol.LINENETAMT) , 0) AS Amount_bought ,
COALESCE( SUM(ol2.QTYORDERED) , 0) AS qty_sales ,
COALESCE( SUM(ol2.LINENETAMT) , 0) AS Amount_sales,
So everything else (p.Value, p.Name, p.M_PRODUCT_ID) must be either in the GROUP BY clause or be aggregated, too ( e.g. MIN(p.Value) ).

Related

Use CTE in SQL to flag DUPLICATES and reference in sub-query

So I have the following CTE:
with dupeinv AS (
select * from (
select
tci.t_idoc,
tci.t_idat,
ROW_NUMBER() OVER (partition by tci.t_idoc ORDER BY tci.t_idoc, tci.t_idat DESC) as rn
from [ln106].[dbo].tcisli305100 tci
) as t
where t.rn = 1
)
There are duplicates in the above table ([ln106].[dbo].tcisli305100) , hence the CTE to get single values. I want to format just these values in the below query (prefixed with ---)
select 'JCI' as BU,
RTRIM(LTRIM(cl.t_orno)) AS SALES_ORDER_NUMBER
, cl.t_pono AS SALES_ORDER_LINE_NUMBER
, CONCAT(cl.t_shpm, cl.t_pono, cl.t_idoc) AS SHIPPING_RECORD_ID
,CASE WHEN cl.t_dqua = 0 or cl.t_dqua is null THEN cl.t_amti ELSE
cl.t_amti / cl.t_dqua END AS AR_INVOICE_LINE_ITEM_PRICE_LOCAL
, cl.t_line AS AR_INVOICE_LINE_NUMBER
, cl.t_dqua AS AR_INVOICE_LINE_ITEM_QUANTITY
--- , concat(dupeinv.t_idoc,'|',format(dupeinv.t_idat,'MMddyyyy') ---
,ci.t_ccur AS AR_INVOICE_CURRENCY
, ci.t_idat AS AR_INVOICE_DATE
FROM [ln106].[dbo].tcisli310100 cl
LEFT JOIN [ln106].[dbo].tcisli305100 ci ON cl.t_idoc = ci.t_idoc
LEFT JOIN t di on cl.t_doc = di_t_doc
LEFT JOIN (SELECT t_orno,t_pono FROM [ln106].[dbo].ttdsls401100 WHERE t_oltp <> 1 group by t_orno,t_pono) as l --Jed 10162020 Changed the join to prevent duplicate records
ON l.t_orno=cl.t_orno COLLATE SQL_Latin1_General_CP1_CI_AS AND l.t_pono=cl.t_pono
LEFT JOIN dupeinv tci on cl.r_idoc = ci.t_doc
WHERE ci.t_idat > '2017'
Query doesn't like me referencing it in the main query. Can anyone help, or suggest a better idea?
Your final query should look something like this:
WITH dupeinv AS
(SELECT *
FROM
(SELECT tci.t_idoc,
tci.t_idat,
ROW_NUMBER() OVER (PARTITION BY tci.t_idoc
ORDER BY tci.t_idoc,
tci.t_idat DESC) AS rn
FROM [ln106].[dbo].tcisli305100 tci) AS t
WHERE t.rn = 1 )
SELECT 'JCI' AS BU,
RTRIM(LTRIM(cl.t_orno)) AS SALES_ORDER_NUMBER ,
cl.t_pono AS SALES_ORDER_LINE_NUMBER ,
CONCAT(cl.t_shpm, cl.t_pono, cl.t_idoc) AS SHIPPING_RECORD_ID ,
CASE
WHEN cl.t_dqua = 0
OR cl.t_dqua IS NULL THEN cl.t_amti
ELSE cl.t_amti / cl.t_dqua
END AS AR_INVOICE_LINE_ITEM_PRICE_LOCAL ,
cl.t_line AS AR_INVOICE_LINE_NUMBER ,
cl.t_dqua AS AR_INVOICE_LINE_ITEM_QUANTITY ,
concat(dupeinv.t_idoc,
'|',
format(dupeinv.t_idat, 'MMddyyyy')) ,
ci.t_ccur AS AR_INVOICE_CURRENCY ,
ci.t_idat AS AR_INVOICE_DATE
FROM [ln106].[dbo].tcisli310100 cl
LEFT JOIN [ln106].[dbo].tcisli305100 ci ON cl.t_idoc = ci.t_idoc
LEFT JOIN t di ON cl.t_doc = di_t_doc
LEFT JOIN
(SELECT t_orno,
t_pono
FROM [ln106].[dbo].ttdsls401100
WHERE t_oltp <> 1
GROUP BY t_orno,
t_pono) AS l --Jed 10162020 Changed the join to prevent duplicate records
ON l.t_orno=cl.t_orno COLLATE SQL_Latin1_General_CP1_CI_AS
AND l.t_pono=cl.t_pono
LEFT JOIN dupeinv tci ON cl.r_idoc = ci.t_doc
WHERE ci.t_idat > '2017'

Combine 3 UNIONed queries into one

I have the following which I would like to do without UNIONs so that the string split is only happening once.
I would also like the results to be in one line per MemberId showing all 3 counts rather than 3 rows.
SELECT MemberKey, 'login' as countType, count(MemberKey) as total FROM [dbo].[CA_MembersAudit]
WHERE isSuccess = 1 and MemberKey IN (SELECT value FROM STRING_SPLIT( #userList, ','))
Group By MemberKey
UNION
SELECT MemberId as MemberKey, 'articles' as countType, count(MemberId) as total FROM [dbo].[CA_Activities]
WHERE StateId = 'Opened' and MemberId IN (SELECT value FROM STRING_SPLIT( #userList, ','))
Group By MemberId
UNION
SELECT MemberId as MemberKey,'assessments' as countType, count(MemberId) as total FROM [dbo].[CA_Activities]
WHERE PercentageComplete is not null AND MemberId IN (SELECT value FROM STRING_SPLIT( #userList, ','))
Group By MemberId
UNION
Can anyone suggest how I should amend the queries into one to be able to do this?
You could use a subquery for each total:
select m.MemberKey,
(select count(*) from CA_MembersAudit ma where m.MemberKey = ma.MemberKey and ma.isSuccess = 1) as 'login_total',
(select count(*) from CA_Activities a where m.MemberKey = a.MemberId and a.stateId = 'Opened') as 'articles_total',
(select count(*) from CA_Activities a where m.MemberKey = a.MemberId and a.PercentageComplete is not null) as 'assessments_total'
from (select value as MemberKey from STRING_SPLIT('1,2,3,4', ',')) m
If your tables have a primary key, you could also do something like this:
select m.MemberKey,
count(distinct ma.Id) 'login_total',
count(distinct a1.Id) 'articles_total',
count(distinct a2.Id) 'assessments_total'
from (select value as MemberKey from STRING_SPLIT('1,2,3,4', ',')) m
left outer join CA_MembersAudit ma on m.MemberKey = ma.MemberKey and ma.isSuccess = 1
left outer join CA_Activities a1 on m.MemberKey = a1.MemberId and a1.stateId = 'Opened'
left outer join CA_Activities a2 on m.MemberKey = a2.MemberId and a2.PercentageComplete is not null
group by m.MemberKey
I believe you can use a CTE and then JOIN to each of the UNION participants.
WITH MemberList AS (
SELECT value AS Member
FROM STRING_SPLIT(#userList, ',')
)
SELECT
MemberKey
,'login' AS countType
,count(MemberKey) AS total
FROM [dbo].[CA_MembersAudit]
JOIN MemberList
ON MemberList.Member = CA_MembersAudit.MemberKey
WHERE isSuccess = 1
GROUP BY MemberKey
UNION
SELECT
MemberId AS MemberKey
,'articles' AS countType
,count(MemberId) AS total
FROM [dbo].[CA_Activities]
JOIN MemberList
ON MemberList.Member = CA_Activities.MemberId
WHERE StateId = 'Opened'
GROUP BY MemberId
UNION
SELECT
MemberId AS MemberKey
,'assessments' AS countType
,count(MemberId) AS total
FROM [dbo].[CA_Activities]
JOIN MemberList
ON MemberList.Member = CA_Activities.MemberId
WHERE PercentageComplete IS NOT NULL
GROUP BY MemberId;
try this :
With MemberList as (
SELECT value as ID FROM STRING_SPLIT( #userList, ',')
),
Activities as (
select f1.MemberId, sum(case when f1.StateId = 'Opened' then 1 else 0 end) as TotalOpened,
sum(case when f1.PercentageComplete is not null then 1 else 0 end) as TotalPercentageComplete
FROM [dbo].[CA_Activities] f1 inner join MemberList f2 on f1.MemberId=f2.ID
where f1.StateId = 'Opened' or f1.PercentageComplete is not null
group by f1.MemberId
),
MemberAudit as (
SELECT f1.MemberKey, count(*) as TotalSuccess
FROM [dbo].[CA_MembersAudit] f1 inner join MemberList f2 on f1.MemberKey=f2.ID
WHERE f1.isSuccess = 1
Group By f1.MemberKey
)
select f1.*, isnull(f2.TotalOpened, 0) as TotalOpened, isnull(f2.TotalPercentageComplete, 0) as TotalPercentageComplete, isnull(f3.TotalSuccess, 0) as TotalSuccess
from MemberList f1
left outer join Activities f2 on f1.ID=f2.MemberId
left outer join MemberAudit f3 on f1.ID=f3.MemberKey
other solution :
SELECT f1.value as ID, isnull(f2.TotalOpened, 0) as TotalOpened, isnull(f2.TotalPercentageComplete, 0) as TotalPercentageComplete, isnull(f3.TotalSuccess, 0) as TotalSuccess
FROM STRING_SPLIT( #userList, ',') f1
outer apply
(
select sum(case when f1.StateId = 'Opened' then 1 else 0 end) as TotalOpened,
sum(case when f1.PercentageComplete is not null then 1 else 0 end) as TotalPercentageComplete
FROM [dbo].[CA_Activities] f1
where (f1.StateId = 'Opened' or f1.PercentageComplete is not null) and f1.MemberId=f1.value
) f2
outer apply
(
SELECT count(*) as TotalSuccess FROM [dbo].[CA_MembersAudit] f1 WHERE f1.isSuccess = 1 and f1.MemberKey=f1.value
) f3

SQL query select record with Max

I have these records below :
CustomerID | Name | Store | Quantity
1 | Elie | HO | 16
1 | Elie | S1 | 4
I would like to filter customers by taking only their max quantity?
I tried it with Max, but the problem I cannot render all the fields with it. If I add main.store in the first line, the second row shows.
Is there any solution?
Select main.CUSTOMER_ID, main.Name
from
(
Select Name = cus.FIRST_NAME + ' ' + cus.LAST_NAME,
Store = cs.NAME
,Transaction_Number = count(ts.TRANSACTION_SUMMARY_ID)
,cus.CUSTOMER_ID
from TRANSACTION_SUMMARY ts
inner join dbo.CUSTOMER cus
on ts.CUSTOMER_ID = cus.CUSTOMER_ID
inner join dbo.CORPORATE_STORE cs
on ts.CORPORATE_STORE_ID = cs.CORPORATE_STORE_ID
Group by cus.CUSTOMER_ID
,cus.FIRST_NAME
,cus.LAST_NAME
,cs.Name
) as main
Group by CUSTOMER_ID
,main.Name
order by main.CUSTOMER_ID
This is a good use of window functions:
with t as (
Select Name = cus.FIRST_NAME + ' ' + cus.LAST_NAME,
Store = cs.NAME,
Transaction_Number = count(ts.TRANSACTION_SUMMARY_ID) , cus.CUSTOMER_ID
from TRANSACTION_SUMMARY ts
inner join dbo.CUSTOMER cus on ts.CUSTOMER_ID = cus.CUSTOMER_ID
inner join dbo.CORPORATE_STORE cs on ts.CORPORATE_STORE_ID = cs.CORPORATE_STORE_ID
Group by cus.CUSTOMER_ID, cus.FIRST_NAME, cus.LAST_NAME, cs.Name
)
select name, store, Transaction_Number, CUSTOMER_ID
from (select t.*,
row_number() over (partition by customer_id order by transaction_number desc) as seqnum
from t
) t
where seqnum = 1;
You can actually dispense with the subquery. However, using window functions with aggregations looks funny at first:
with t as (
Select Name = cus.FIRST_NAME + ' ' + cus.LAST_NAME,
Store = cs.NAME,
Transaction_Number = count(ts.TRANSACTION_SUMMARY_ID) , cus.CUSTOMER_ID,
row_number() over (partition by cus.CUSTOMER_ID
order by count(ts.TRANSACTION_SUMMARY_ID) desc
) as seqnum
from TRANSACTION_SUMMARY ts
inner join dbo.CUSTOMER cus on ts.CUSTOMER_ID = cus.CUSTOMER_ID
inner join dbo.CORPORATE_STORE cs on ts.CORPORATE_STORE_ID = cs.CORPORATE_STORE_ID
Group by cus.CUSTOMER_ID, cus.FIRST_NAME, cus.LAST_NAME, cs.Name
)
select name, store, Transaction_Number, CUSTOMER_ID
from t
where seqnum = 1;
Please try:
select * From tbl a
where a.Quantity=
(select MAX(b.Quantity) from tbl b where a.CustomerID=b.CustomerID)
what you want is
select customer_id, max( quantity )
from main
group by customer_id
then you can use this to join to itself if you want
select *
from main
, (
select customer_id, max( quantity ) qty
from main
group by customer_id
) m
where main.customer_id = m.customer_id
and main.quantity = m.qty
Obviously, name has no business being in this table, but you included it, so I did too...
SELECT x.*
FROM my_table x
JOIN
( SELECT customerid
, name
, MAX(quantity) max_quantity
FROM my_table
GROUP
BY customerid
, name
) y
ON y.customerid = x.customerid
AND y.name = x.name
AND y.max_quantity = x.quantity;

SQL join two simple query with count and groupby

hello i have 2 queries and i wanna join together but i don't know how...
SELECT *, count(*) as invii
FROM professionisti JOIN preventivi_invii ON
professionisti.email=preventivi_invii.email
GROUP BY professionisti.email
HAVING invii> 300
SELECT *, count(*) as acquisti
FROM professionisti JOIN contatti_acquistati ON
professionisti.email=contatti_acquistati.email
GROUP BY professionisti.email
HAVING acquisti> 5
the problem for me is multiple count and the group by with same column.
thank u
How about the below query. You would just change the WHERE clause to meet your needs.
SQL Fiddle Example:
SELECT * FROM
(
SELECT p.email,
CASE WHEN ISNULL(m1.invii) THEN 0 ELSE m1.invii END AS invii,
CASE WHEN ISNULL(m2.acquisti) THEN 0 ELSE m2.acquisti END AS acquisti
FROM professionisti p
LEFT JOIN
(
SELECT pp.email, COUNT(*) AS invii
FROM preventivi_invii pp
GROUP BY pp.email
) AS m1 ON p.email = m1.email
LEFT JOIN
(
SELECT c.email, COUNT(*) AS acquisti
FROM contatti_acquistati c
GROUP BY c.email
) AS m2 ON p.email = m2.email
) AS mm
WHERE mm.invii = 0
OR mm.acquisti = 0;
Or you could use:
SELECT * FROM
(
SELECT p.email,
(
SELECT
CASE WHEN ISNULL(COUNT(*)) THEN 0 ELSE COUNT(*) END
FROM preventivi_invii pp
WHERE pp.email = p.email
) AS invii,
(
SELECT
CASE WHEN ISNULL(COUNT(*)) THEN 0 ELSE COUNT(*) END
FROM contatti_acquistati c
WHERE c.email = p.email
) AS acquisti
FROM professionisti p
) AS mm
WHERE mm.invii = 0
OR mm.acquisti = 0

How does a sub query in the from clause work?

What is a valid use-case for Sub Query in the FROM clause? How does that scheme work? There are many examples of this type in SO. A link to one of those is here but I can't see how this scheme works.
P.S: If the answer is Oracle specific it is fine.
Here are some use cases for a subquery in the from clause. How it works has been explained in the comments to your question (SQL is mathematical closed thanks to its relational operators).
1. Pivot (SQL Server 2008)
select P.RUN_ID
, [2012] = sum(P.[2012])
, [2013] = sum(P.[2013])
, [2014] = sum(P.[2014])
, [2015] = sum(P.[2015])
from (select T.RUN_ID
, Y.YEAR
, T.MEASURE
from SOME_TABLE T
inner join
YEAR Y
on T.SOME_ID = Y.SOME_ID
) T
pivot (
sum(MEASURE)
for YEAR in ([2012], [2013], [2014], [2015])
) P
group by
P.RUN_ID
order by
P.RUN_ID
2. over clause (Oracle) based on a union
select S.Text_ID
, row_number() over (partition by S.Text_ID order by S.Segmentstart) as Segmentnumber
, S.Segment_ID
, S.Segmentstart
, S.Segmentend
, S.Segmentfragment
from (select S.Text_ID as Text_ID
, S.Satz_ID as Segment_ID
, S.Start as Segmentstart
, S.End as Segmentend
, S.Fragment as Segmentfragment
from Mainclauses S
union all
select X.ID as Text_ID
, null as Segment_ID
, coalesce(S.End, 0) as Segmentstart
, lead(S.Start, 1, X.CONTENT_LENGTH) over (partition by X.ID order by S.Start) as Segmentend
, 'X' as Segmentfragment
from Texts X
left join
Mainclauses S
on X.ID = S.Text_ID
union all
select X.ID as Text_ID
, null as Segment_ID
, 0 as Segmentstart
, min(S.Start) as Segmentend
, 'X' as Segmentfragment
from Texts X
inner join
Mainclauses S
on X.ID = S.Text_ID
group by
X.ID
) S
3. over clause (SQL Server 2008) with join and aggregate
select E.X_ID
, Z.SomeThing
, sum(Z.OtherMeasure * E.Measure) as CombinedMeasure
, Sorting = row_number() over
( partition by
E.X_ID
order by
Z.SomeThing
)
from (select E.X_ID
, E.Y_ID
, Measure = sum(E.Measure)
from SomeTable E
group by
E.X_ID
, E.Y_ID
) E
inner join
OtherTable Z
on E.Y_ID = Z.Y_ID
4. Calculate ratio (SQL Server 2008)
with SomeData
( Main_ID
, Sub_ID
, Measure
)
as (select Main_ID
, Sub_ID
, Measure = sum(Measure)
from SomeTable P
group by
Main_ID
, Sub_ID
)
select Main_ID
, Sub_ID
, Ratio = D.Measure / sum(M.Measure) over (partition by M.Main_ID)
from SomeData D
inner join
(select Main_ID
, Measure = sum(Measure)
from SomeData
group by
Main_ID
having sum(Measure) != 0
) M
on M.Main_ID = D.Main_ID
5. Partial Comparision of two (or more) tables (SQL Server 2008)
select *
from (select A, M = sum(M) from S group by A) X
full outer join
(select A, M = sum(M) from T group by A) Y
on X.A = Y.A
where X.A is null
or Y.A is null
or abs(X.M - Y.M) > 0.00000001
Note: These are examples only and in I thought that the subquery in the from clause have been a good solution to achieve the result.