SQL query Group by while using Union All - sql

I am completely New to SQL queries and need help in combining some select statements together to form one single query.
I will start one query at a time:
select sum(DOCI)
from (
select POL.SP_NUM, sum(Q.AMT + POL.AMT) DOCI
from S_ASSET POL
, S_QUOTE_ITEM Q
where POL.X_QUOTE_ID = Q.ROW_ID
and POL.SP_NUM in ('000','111','222')
group by POL.SP_NUM
UNION ALL
select POL.SP_NUM, sum(QXM.AMT) DOCI
from S_ASSET POL
, S_QUOTE_ITEM Q
, S_QUOTE_ITEM_XM QXM
where POL.X_QUOTE_ID = Q.ROW_ID
and Q.ROW_ID = QXM.PAR_ROW_ID
and POL.SP_NUM in ('000','111','222')
group by POL.SP_NUM
)
Tables:
S_ASSET
X_QUOTE_ID POL AMT
A 000 1
B 111 1
C 222 1
S_QUOTE_ITEM
ROW_ID AMT
A 10
B 10
C 1
S_QUOTE_ITEM_XM
PAR_ROW_ID AMT
A 10
B 0
Expected O/P:
POL AMT(sum)
A 21
B 11
C 2
Please help

SELECT sp_num, SUM(doci)
FROM ( ...subquery... )
GROUP BY sp_num;
The table name pol only exists inside the subquery. The outer query is selecting from the result of the subquery, not from any named table.

Related

How to generate loop kind of behaviour in SQL query to fetch multiple queries & compare results?

I am unable to generate a looping kind of behaviour in a SQL query.
I am having two tables:
Table A
Id Brand Prod_Id Alt_Prod_Id
1 A 2 5
2 B 3 9
3 C 5 9
Table B
Id Prod_Id Rate
1 2 5
2 3 9
2 5 7
2 9 9
Rate in Table B needs to be looked up for each brands Prod_ID & Alt_Prod_Id & select the least value between 2 found value
The expected result / output is:
Brand Min_Prod_Val
A 5
B 9
C 7
Can this be done in a query?
Thanks!
You could join tableb twice (once for prod_id, another for alt_prod_id), and then select the smallest rate:
select
a.brand,
least(b1.rate, b2.rate) min_prod_val
from tablea a
inner join tableb b1 on b1.prod_id = a.prod_id
inner join tableb b2 on b2.prod_id = a.alt_prod_id
It is unclear which database you are using. If that's SQL Server: it does not support least(), so you need a case expression:
case when b1.rate < b2.rate then b1.rate else b2.rate end min_prod_val
You can use a single join and GROUP BY the brand:
SELECT a.Brand,
MIN( b.rate ) AS min_prod_val
FROM TableA A
INNER JOIN TableB b
ON ( b.prod_id IN ( a.prod_id, a.alt_prod_id ) )
GROUP BY a.Brand
Or you can use a correlated sub-query:
SELECT a.Brand,
(
SELECT MIN( rate )
FROM TableB b
WHERE b.prod_id IN ( a.prod_id, a.alt_prod_id )
) AS min_prod_val
FROM TableA A
db<>fiddle

sql table using sum

I would like a result of
ID received total
2 25 25
from ItemReceived table
ID item received
2 1 5
2 2 2
2 1 10
2 2 8
and ItemsToReceive table
ID item quantity
2 1 15
2 2 10
Is there a way to get this result?
I used this code:
SELECT sum(ItemsToReceive.quantity), SUM( ItemReceived.received)
FROM ItemsToReceive
INNER JOIN ItemReceived ON ItemReceived.ID = ItemsToReceive.ID
GROUP BY poitems.poid
I got a wrong result making received to 50...
Can anyone help me?
Try this
select t1.Id,t1.quantity, t2.received from
(
SELECT ID,sum(quantity) quantity from ItemsToReceive group by id
) as t1 inner join
(
SELECT ID,SUM(received) as received from ItemReceived group by id
) as t2 on t1.id=t2.id
This might help
;WITH quantity AS (
SELECT sum(ItemsToReceive.quantity) As TotQuant
,ItemsToReceive.id AS id
FROM ItemsToReceive
GROUP BY ItemsToReceive.id
), Prod As (
SELECT SUM( ItemReceived.received) As TotRec
,ItemReceived.ID As Id
FROM ItemReceived
GROUP BY ItemReceived.ID
)
SELECT
q.Id
,p.TotRec As Received
,q.TotQuant As Quantity
FROM quantity q
INNER JOIN Prod p on p.Id = q.id
select ID , sum(received) , sum(quantity) from ItemReceived left join ItemsToReceive on (ItemReceived.ID = ItemsToReceive.ID and ItemReceived.item = ItemsToReceive.item) group by ID

Group By syntax while using Cross Join

i wish to apply a Group By condition to my SQL below so that the O/P will display POL# with GP.
select t.POl#, (DEB.CUSTD - CRED.CUSTC) AS GP
from (
(
select POL.SP_NUM POL#
, sum(D.AMT) AS CUSTD
from S_INVOICE D
, S_ASSET POL
where POL.ROW_ID = D.FN_ACCNT_ID
and POL.SP_NUM in ('000','111','222')
and D.DEBIT_TYPE = 'Customer'
group by POL.SP_NUM
) DEB
CROSS JOIN
(
select pol.SP_NUM POL#
, sum(C.AMT) AS CUSTC
from S_SRC_PAYMENT C
, S_ASSET POL
where POL.ROW_ID = C.ASSET_ID
and POL.SP_NUM in ('000','111','222')
and C.CG_DEDN_TYPE_CD = 'Customer'
group by POL.SP_NUM
) CRED
) t
group by t.POL#
When i execute the same I am getting "ORA-00933: SQL command not properly ended" error, where the cursor points to 't'
Kindly assist.
Expected O/P:
POL# GP
000 800
111 120
222 50
Appending Sample Data with explanation for better understanding of requirement:
Table 1:
S_ASSET
ROW_ID POL#
1 000
2 111
3 222
4 333
5 444
Table 2:
S_INVOICE (Debit Table)
FN_ACCNT_ID POL# DEBIT_TYPE AMT
1 000 Customer 10
1 000 Customer 10
1 000 Insurer 5
2 111 Customer 10
3 222 Customer 10
3 222 Insurer 5
5 444 Insurer 10
Table 3:
S_SRC_PAYMENT (Credit Table)
ASSET_ID POL# CG_DEDN_TYPE_CD AMT
1 000 Insurer 10
1 000 Insurer 10
1 000 Customer 5
2 111 Insurer 10
3 222 Insurer 5
3 222 Insurer 5
3 222 Customer 5
5 444 Customer 10
As per this query I will consider "Customer" records per POL# and SUM the AMT. (Every Debit for the Customer will Credit Insurer(s) per POL# & vice-versa)
Expected O/P (Sum of Debits - Sum of Credits) for a Customer per POL#
POL # AMT (GP)
000 15
111 10
222 5
333 0
444 -10
You obviously only want to get the deb and cred per s_asset and then aggregate so as to get the sums. You can do this without a join and subquery the sums directly instead:
select
sp_num as pol#,
sum(<get deb sum for the pol.row_id here>) - sum(<get cred sum for the pol.row_id here>)
from s_asset pol
where sp_num in ('000','111','222')
group by sp_num;
The complete query:
select
sp_num as pol#,
coalesce(sum(
(
select sum(deb.amt)
from s_invoice deb
where deb.fn_accnt_id = pol.row_id
and deb.debit_type = 'Customer'
)
), 0) -
coalesce(sum(
(
select sum(cred.amt)
from s_src_payment cred
where cred.asset_id = pol.row_id
and cred.cg_dedn_type_cd = 'Customer'
), 0)
) as gp
from s_asset pol
where sp_num in ('000','111','222')
group by sp_num;
The same with joins instead:
select
pol.sp_num as pol#,
coalesce(sum(deb.total), 0) - coalesce(sum(cred.total), 0) as gp
from s_asset pol
left join
(
select fn_accnt_id as pol_row_id, sum(deb.amt) as total
from s_invoice
where debit_type = 'Customer'
group by fn_accnt_id
) deb on deb.pol_row_id = pol.row_id
left join
(
select asset_id as pol_row_id, sum(amt) as total
from s_src_payment
where cg_dedn_type_cd = 'Customer'
group by asset_id
) cred on cred.pol_row_id = pol.row_id
group by pol.sp_num;
This syntax
from ( (select ...) CROSS JOIN (select ...) )
is invalid. A JOIN belongs to a FROM. So either of these would be correct:
from ( SELECT * FROM (select ...) CROSS JOIN (select ...) )
or
from (select ...) CROSS JOIN (select ...)
However, are you sure you want a CROSS JOIN at all? Both subqueries give you POL numbers plus data, bat rather than joining them on POL#, you cross join the results, so you get all POL# combinations instead.

left join without duplicate values using MIN()

I have a table_1:
id custno
1 1
2 2
3 3
and a table_2:
id custno qty descr
1 1 10 a
2 1 7 b
3 2 4 c
4 3 7 d
5 1 5 e
6 1 5 f
When I run this query to show the minimum order quantities from every customer:
SELECT DISTINCT table_1.custno,table_2.qty,table_2.descr
FROM table_1
LEFT OUTER JOIN table_2
ON table_1.custno = table_2.custno AND qty = (SELECT MIN(qty) FROM table_2
WHERE table_2.custno = table_1.custno )
Then I get this result:
custno qty descr
1 5 e
1 5 f
2 4 c
3 7 d
Customer 1 appears twice each time with the same minimum qty (& a different description) but I only want to see customer 1 appear once. I don't care if that is the record with 'e' as a description or 'f' as a description.
First of all... I'm not sure why you need to include table_1 in the queries to begin with:
select custno, min(qty) as min_qty
from table_2
group by custno;
But just in case there is other information that you need that wasn't included in the question:
select table_1.custno, ifnull(min(qty),0) as min_qty
from table_1
left outer join table_2
on table_1.custno = table_2.custno
group by table_1.custno;
"Generic" SQL way:
SELECT table_1.custno,table_2.qty,table_2.descr
FROM table_1, table_2
WHERE table_2.id = (SELECT TOP 1 id
FROM table_2
WHERE custno = table_1.custno
ORDER BY qty )
SQL 2008 way (probably faster):
SELECT custno, qty, descr
FROM
(SELECT
custno,
qty,
descr,
ROW_NUMBER() OVER (PARTITION BY custno ORDER BY qty) RowNum
FROM table_2
) A
WHERE RowNum = 1
If you use SQL-Server you could use ROW_NUMBER and a CTE:
WITH CTE AS
(
SELECT table_1.custno,table_2.qty,table_2.descr,
RN = ROW_NUMBER() OVER ( PARTITION BY table_1.custno
Order By table_2.qty ASC)
FROM table_1
LEFT OUTER JOIN table_2
ON table_1.custno = table_2.custno
)
SELECT custno, qty,descr
FROM CTE
WHERE RN = 1
Demolink

How to get this result with and only with SQL?

The question is:
Two tables (t1, t2)
Table t1:
SELLER | NON_SELLER
A B
A C
A D
B A
B C
B D
C A
C B
C D
D A
D B
D C
Table t2:
SELLER | COUPON | BAL
A 9 100
B 9 200
C 9 300
D 9 400
A 9.5 100
B 9.5 20
A 10 80
Using SELECT Statement to get this result:
SELLER| COUPON | SUM(BAL)
A 9 900
B 9 800
C 9 700
D 9 600
A 9.5 20
B 9.5 100
C 9.5 120
D 9.5 120
A 10 0 # !!!
B 10 80
C 10 80
D 10 80
For seller A SUM(BAL) means sum( B.BAL,C.BAL,D.BAL), for B, SUM(BAL)=SUM(A.BAL,C.BAL,D.BAL)...
Please find a way with good performance and don't use temporary table.
My solution:
Running this query will get the result but without the row "A 10 0":
select t1.seller, t2.coupon, sum(bal)
from t1, t2
where t1.non_seller = t2.seller
group by t1.seller, t2.coupon
order by t2.coupon
Please help ~~~~~~
If I understand you correctly, you're looking for data on all sellers and all coupons. So let's start with a cross join that generates a list of coupons and sellers:
select sellers.seller
, coupons.coupon
from (
select distinct seller
from Table2
) as sellers
cross join
(
select distinct coupon
from Table2
) as coupons
For each seller-coupon combination, you're looking for the sum they can buy from other sellers. This can be accomplished by a left join:
select sellers.seller
, coupons.coupon
, case when sum(t2.bal) is null then 0 else sum(t2.bal) end
from (
select distinct seller
from Table2
) as sellers
cross join
(
select distinct coupon
from Table2
) as coupons
left join
Table2 t2
on t2.seller <> sellers.seller
and t2.coupon = coupons.coupon
group by
sellers.seller
, coupons.coupon
The only function of the case statement is to replace a null sum with a 0.
The output matches the one in your answer. Note that this solution doesn't use Table1: the list of other sellers is produced by the t2.seller <> sellers.seller condition in the left join.
I get another way to this:
select t1.seller, t2.coupon, sum(bal)
from t1, t2
where t1.non_seller = t2.seller
group by t1.seller, t2.coupon
union
(select seller,coupon,0 from t2 group by coupon having count(seller) == 1);
And I don't know if it is better or worst than compare with #Andomar :
select sellers.seller
, coupons.coupon
, case when sum(t2.bal) is null then 0 else sum(t2.bal) end
from (
select distinct seller
from Table2
) as sellers
cross join
(
select distinct coupon
from Table2
) as coupons
left join
Table2 t2
on t2.seller <> sellers.seller
and t2.coupon = coupons.coupon
group by
sellers.seller
, coupons.coupon