Query from different tables - sql

I have 2 tables
TABLE A
INV AMT DISC
1001 1500 150
1002 3000 300
TABLE B
INV DESC AMT
1001 CHARGES 100
1001 FREIGHT 30
1001 INSURANCE 20
1002 CHARGES 215
1002 FREIGHT 32
1002 INSURANCE 25
To combine both tables, I used the following query (given by Mikael Eriksson):-
select
A.inv,
A.amount,
A.disc,
B.charges,
B.freight,
B.insurance
from #TableA as A
inner join (
SELECT t.inv,
MAX(CASE WHEN t.description = 'CHARGES' THEN t.amount ELSE NULL END) AS charges,
MAX(CASE WHEN t.description = 'FREIGHT' THEN t.amount ELSE NULL END) AS freight,
MAX(CASE WHEN t.description = 'INSURANCE' THEN t.amount ELSE NULL END) AS insurance
FROM #TableB as t
GROUP BY t.inv) as B
on A.inv = B.inv
Then, I'll have the following output:-
INV AMT DISC CHARGES FREIGHT INSURANCE
1001 1500 150 100 30 20
1002 3000 300 215 32 25
Question, how can I add a query into the earlier statement if I want say, where charges is equal to 100. The final result will look like this:-
INV AMT DISC CHARGES FREIGHT INSURANCE
1001 1500 150 100 30 20

select
A.inv,
A.amt,
A.disc,
B.charges,
B.freight,
B.insurance
from TableA as A
inner join (
SELECT t.inv,
MAX(CASE WHEN t.descr = 'CHARGES' THEN t.amt ELSE NULL END) AS charges,
MAX(CASE WHEN t.descr = 'FREIGHT' THEN t.amt ELSE NULL END) AS freight,
MAX(CASE WHEN t.descr = 'INSURANCE' THEN t.amt ELSE NULL END) AS insurance
FROM TableB as t
GROUP BY t.inv) as B
on A.inv = B.inv
where charges = 100 --<< just add this
Depending on how many rows contain tableb.amt = 100 and descr = 'charges', you may be better off writing the query this way.
select a.inv, a.amt, a.disc,
b.amt AS charges,
c.amt AS freight,
d.amt AS insurance
from tablea a
inner join tableb b on b.inv = a.inv and b.descr = 'CHARGES' and b.amt = 100
left join tableb c on c.inv = a.inv and c.descr = 'FREIGHT'
left join tableb d on d.inv = a.inv and d.descr = 'INSURANCE'
Test Data
create table tablea (inv int, amt int, disc int);
insert tablea select 1001,1500,150;
insert tablea select 1002,3000,300;
create table tableb (inv int, descr varchar(10), amt int);
insert tableb select 1001, 'CHARGES', 100;
insert tableb select 1001, 'FREIGHT', 30;
insert tableb select 1001, 'INSURANCE', 20;
insert tableb select 1002, 'CHARGES', 215;
insert tableb select 1002, 'FREIGHT', 32;
insert tableb select 1002, 'INSURANCE', 25;
Output
inv amt disc charges freight insurance
----------- ----------- ----------- ----------- ----------- -----------
1001 1500 150 100 30 20
Warning: Null value is eliminated by an aggregate or other SET operation.
(1 row(s) affected)
Note: Using the proposed 2nd query, the warning is not present in the output

Related

To select data from multiple records in SQL Server having a common ID

I need to select/concat data from 2 tables in SQL Server I'm using Left Join, but the data is returned as multiple records.
Below are the sample tables
Table1
Id Name Age
1 Sk 20
2 Rb 30
Table2
ID Bike Price Table1Id
1 RX 200 1
2 CD 250 1
3 FZ 300 1
4 R1 400 2
The desired output is
ID Name Age Bike1 Price1 Bike2 Price2 Bike3 Price3
1 Sk 20 RX 200 CD 250 FZ 300
2 Rb 30 R1 400 NULL NULL NULL NULL
A sample format of the query I'm using
SELECT A.ID, A.Name, B.Bike, B.Price FROM Table1 A LEFT JOIN Table2 B ON
A.id = B.Table1Id order by A.id
The output I'm getting from the above query is
ID Name Age Bike Price
1 Sk 20 RX 200
1 Sk 20 CD 250
1 Sk 20 FZ 300
2 Rb 30 R1 400
I need the data as one record for a particular ID and not multiple records (As seen in the desired output). Tired using offset, but offset will return only limited result not the entire records.
Any suggestions on how this can be achieved?
If you know the maximum number of bikes per person, you can use conditional aggregation:
SELECT ID, Name,
MAX(CASE WHEN seqnm = 1 THEN Bike END) as bike_1,
MAX(CASE WHEN seqnm = 1 THEN Price END) as price_1,
MAX(CASE WHEN seqnm = 2 THEN Bike END) as bike_2,
MAX(CASE WHEN seqnm = 2 THEN Price END) as price_2,
MAX(CASE WHEN seqnm = 3 THEN Bike END) as bike_3,
MAX(CASE WHEN seqnm = 3 THEN Price END) as price_3
FROM (SELECT A.ID, A.Name, B.Bike, B.Price,
ROW_NUMBER() OVER (PARTITION BY A.id ORDER BY B.Price) as seqnum
FROM Table1 A LEFT JOIN
Table2 B
ON A.id = B.Table1Id
) ab
GROUP BY ID, Name,
ORDER BY id

Using Not in in SQL query

I have two tables billcrown and bank_details.
In billcrown there exist a unique row for each PJNO:
PJNO GRIRNO AMT
---- ------ ----
PJ1 GRIR1 1000
PJ2 GRIR2 150
Table bankdetails has
PJNO GRIRNO AMT
---- ------ ---
PJ1 GRIR1 100
PJ2 GRIR2 150
PJ1 GRIR1 200
I want to display all PJNO of the table billcrown where the sum of AMT of this PJNO in bankdetails is not equal to the AMT of this PJNO in billcrown
Here PJ1 in billcrown's amount is 1000 but the sum of amounts in bankdetails for the PJ1 is 300. So it should be displayed. But in the case of PJ2 the billcrown and bankdetails amount is the same.
Something like this, perhaps?
select c.pjno
from billcrowm c join bankdetails d on d.pjno = c.pjno
group by c.pjno
having sum(c.amt) <> sum(d.amt);
[EDIT, after new information has been revealed]
Outer join with NVL might do the job.
select c.pjno
from billcrowm c left join bankdetails d on c.pjno = d.pjno
group by c.pjno
having sum(c.amt) <> nvl(sum(d.amt), 0);
[EDIT #2, after reading Sharad's comment]
with csum as
(select pjno, grirno, sum(amt) amt
from billcrowm
group by pjno, grirno
),
dsum as
(select pjno, grirno, sum(amt) amt
from bankdetails
group by pjno, grirno
)
select c.pjno
from csum c left join dsum d on c.pjno = d.pjno
group by c.pjno
having sum(c.amt) <> sum(nvl(d.amt, 0));
SELECT b.PJNO FROM billcrowm b
LEFT JOIN
(
SELECT PJNO, sum(amt) AS total_amt FROM bankdetails GROUP BY PJNO
)d
ON b.PJNO = d.PJNO
WHERE COALESCE(b.amt,0) <> COALESCE(d.total_amt,0);
IF OBJECT_ID('tempdb..#myTemp') IS NOT NULL
DROP TABLE #myTemp
SELECT * INTO #myTemp FROM
(SELECT PJNO, SUM(AMT) AS Amount FROM
bankdetails
GROUP BY PJNO)
AS tempResult
SELECT T.[PJNO], T.Amount, (T1.AMT - T.Amount) As AmountDiff
FROM #myTemp T
INNER JOIN billcrowm T1 ON T.[PJNO] = T1.[PJNO]
WHERE T.Amount <> T1.AMT
This would work.
with BankDetailsCTE
as
(
Select PJNO, sum(AMT) as amt from BankDetails group by PJNO
)
Select d.Pjno from Billcrown d
left join BankDetailsCTE c
on d.pjno = c.pjno
where d.AMT <> c.amt or c.amt is null
If I understand well, all you need is a GROUP BY with an OUTER JOIN.
With these tables:
create table billcrown (PJNO, GRIRNO, AMT) as (
select 'PJ1', 'GRIR1', 1000 from dual union
select 'PJ2', 'GRIR2', 150 from dual union
select 'PJXX','XXXXX', 100 from dual
);
create table bankdetails (PJNO, GRIRNO, AMT) as (
select 'PJ1', 'GRIR1', 100 from dual union
select 'PJ2', 'GRIR2', 150 from dual union
select 'PJ1', 'GRIR1', 200 from dual
);
this
select bc.PJNO, bc.GRIRNO, bc.AMT, sum(bd.amt)
from billCrown bc
left join bankDetails bd
on (bd.PJNO = bc.PJNO
and bd.GRIRNO = bc.GRIRNO -- do you need this?
)
group by bc.PJNO, bc.GRIRNO, bc.AMT
having sum(nvl(bd.amt, 0)) != bc.amt
gives:
PJNO GRIRNO AMT SUM(BD.AMT)
---- ------ ---------- -----------
PJXX XXXXX 100
PJ1 GRIR1 1000 300

SQL - SUM within subquery

I have the following code that looks at the SalesVol of different products and groups it by transaction_week
SELECT a.transaction_week,
SUM(CASE WHEN record_type IN (6,37,13) THEN quantity ELSE 0 END) as SalesVol
FROM table 1 a
LEFT JOIN table 2 b ON b.Date = a.transaction_date
LEFT JOIN table 3 c ON c.sku = a.product
WHERE series in (62,236,501,52)
GROUP BY a.transaction_week
ORDER BY a.transaction_week
| tw | SalesVol |
| 1 | 4768 |
| 2 | 4567 |
| 3 | 4354 |
| 4 | 4678 |
I want to be able to have multiple subqueries where I change the series numbers for example.
SELECT a.transaction_week,
(SELECT SUM(CASE WHEN record_type IN (6,37,13) THEN quantity ELSE 0 END) as SalesVol
FROM table 1 a
LEFT JOIN table 2 b ON b.Date = a.transaction_date
LEFT JOIN table 3 c ON c.sku = a.product
WHERE series in (62,236,501,52)) as personal care
(SELECT SUM(CASE WHEN record_type IN (6,37,13) THEN quantity ELSE 0 END) as SalesVol
FROM table 1 a
LEFT JOIN table 2 b ON b.Date = a.transaction_date
LEFT JOIN table 3 c ON c.sku = a.product
WHERE series in (37,202,203,456)) as white goods
FROM table 1 a
LEFT JOIN table 2 b ON b.Date = a.transaction_date
LEFT JOIN table 3 c ON c.sku = a.product
GROUP BY a.transaction_week
ORDER BY a.transaction_week
I can't get the subqueries at work as it is giving me the overall sum value and not grouping it by transaction_week
Instead of using subqueries, add series to the condition of the CASE statements:
SELECT a.transaction_week,
sum(CASE WHEN series IN (62,236,501,52) AND record_type IN (6,37,13)
THEN quantity ELSE 0 END) as personal_care,
sum(CASE WHEN series IN (37,202,203,456) AND record_type IN (6,37,13)
THEN quantity ELSE 0 END) as white_goods
FROM table 1 a
LEFT JOIN table 2 b ON b.Date = a.transaction_date
LEFT JOIN table 3 c ON c.sku = a.product
GROUP BY a.transaction_week
ORDER BY a.transaction_week;
You just miss the a.transaction_week in you subquery. The JOIN in outer query is unneccessary.
SELECT a.transaction_week,
(
SELECT SUM(CASE WHEN record_type IN (6,37,13) THEN quantity ELSE 0 END) as SalesVol
FROM table 1 a2
LEFT JOIN table 2 b ON b.Date = a2.transaction_date
LEFT JOIN table 3 c ON c.sku = a2.product
WHERE series in (62,236,501,52) AND a2.transaction_week = a.transaction_week
) as personal care,
(
SELECT SUM(CASE WHEN record_type IN (6,37,13) THEN quantity ELSE 0 END) as SalesVol
FROM table 1 a 2
LEFT JOIN table 2 b ON b.Date = a2.transaction_date
LEFT JOIN table 3 c ON c.sku = a2.product
WHERE series in (37,202,203,456) AND a2.transaction_week = a.transaction_week
) as white goods
FROM table 1 a
GROUP BY a.transaction_week
ORDER BY a.transaction_week
Try this it would work fast as well as up to your requirement:
SELECT a.transaction_week ,
whitegoods.SalesVol AS 'White Goods' ,
personalcare.SalesVol1 AS 'Personal Care'
FROM table1 a
LEFT JOIN table2 b ON b.[Date] = a.transaction_date
LEFT JOIN table3 c ON c.sku = a.product
CROSS APPLY ( SELECT SUM(CASE WHEN record_type IN ( 6, 37, 13 )
THEN quantity
ELSE 0
END) AS SalesVol
FROM table1 a2
WHERE b.[Date] = a2.transaction_date
AND c.sku = a2.product
AND series IN ( 37, 202, 203, 456 )
AND a2.transaction_week = a.transaction_week
) whitegoods
CROSS APPLY ( SELECT SUM(CASE WHEN record_type IN ( 6, 37, 13 )
THEN quantity
ELSE 0
END) AS SalesVol1
FROM table1 a2
WHERE b.[Date] = a2.transaction_date
AND c.sku = a2.product
AND series IN ( 62, 236, 501, 52 )
AND a2.transaction_week = a.transaction_week
) personalcare
GROUP BY a.transaction_week
ORDER BY a.transaction_week
You should use the UNION operator. Please refer to the query below:
select a.transaction_week, SalesVol from
(SELECT a.transaction_week as transaction_week,
SUM(CASE WHEN record_type IN (6,37,13) THEN quantity ELSE 0 END) as SalesVol
FROM table 1 a
LEFT JOIN table 2 b ON b.Date = a.transaction_date
LEFT JOIN table 3 c ON c.sku = a.product
WHERE series in (62,236,501,52)
UNION
SELECT a.transaction_week as transaction_week,
SUM(CASE WHEN record_type IN (6,37,13) THEN quantity ELSE 0 END) as SalesVol
FROM table 1 a
LEFT JOIN table 2 b ON b.Date = a.transaction_date
LEFT JOIN table 3 c ON c.sku = a.product
WHERE series in (37,202,203,456)
) AS tbl1
GROUP BY tbl1.transaction_week
ORDER BY tbl1.transaction_week

SQL query for combining data from the same table

I have this table :
create table mytable
(ID varchar(10), VNDCOD INT, MANUF varchar(10), PRICE INT, COST INT);
insert into mytable values
('4', 1000, 'AG', 5455, 9384),
('4', 1000, 'A1', 16, 31),
('4', 2000, 'AG', 5253, 8339)
I want to be able to select something like this:
ID MANUF PRICE COST PRICE COST
4 AG 5455 9384 5253 8339
4 A1 16 31
If there is two MANUF for an ID, we should combine them on one line where the PRICE and COST of the one with VNDCOD 1000 is on the left and VNDCOD 2000 on the right like in my expected result. I don't know if it is possible to do this in one query. Any help would be greatly appreciated.
Either use a self-join or a MAX(CASE) (fiddle):
select t1.ID, t1.MANUF, t1.PRICE, t1.COST, t2.PRICE, t2.COST
from mytable as t1 left join mytable as t2
on t1.ID = t2.ID
and t1.MANUF = t2.MANUF
and t2.VNDCOD = 2000
where t1.VNDCOD = 1000
;
select ID, MANUF,
max(case when VNDCOD = 1000 then PRICE end),
max(case when VNDCOD = 1000 then COST end),
max(case when VNDCOD = 2000 then PRICE end),
max(case when VNDCOD = 2000 then COST end)
from mytable
group by ID, MANUF
You can readily do this with conditional aggregation:
select id,
max(case when vndcode = 1000 then price end) as price_1000,
max(case when vndcode = 1000 then cost end) as cost_1000,
max(case when vndcode = 2000 then price end) as price_2000,
max(case when vndcode = 2000 then cost end) as cost_2000
from mytable t
group by id;

Sql Case Column 1 and Column same value then apply calculation

I would like apply calculation in CASE Statement, but the result is not I'm expected and I'm not sure how to apply the query to filter date(depend on month). What is the problem with my query?? Please help... Thank you
this is my query
SELECT DISTINCT a.SERVICE_CODE,
CASE WHEN
b.SERVICE_CODE IS NULL THEN a.AMT ELSE SUM (a.AMT) - SUM(b.AMT) END AS TOTAL_AMT
FROM Table a
LEFT OUTER JOIN Table b ON (a.SERVICE_CODE = b.SERVICE_CODE)
WHERE b.SERVICE_CODE >='3000' AND c.SERVICE_CODE >='3000'
Table a
Invoice_No date Service_code Amt
001 1/7/2014 6000 300
002 1/8/2014 6003 700
003 5/8/2014 6003 100
004 10/8/2014 6005 1000
Table b
Credit_No date Service_code Amt
c100 1/7/2014 6000 300
c200 13/8/2014 6003 700
Desired output
Service_code Total_Amt
6003 100
6005 1000
Thank you
try like this
In MYSQL
select t1.SERVICE_CODE,(t1.amt- case when c.amt is null then 0 else c.amt end)
as AMT from t1 c right outer join (select t.Invoice_No,SERVICE_CODE,
sum(amt) as amt from t group by SERVICE_CODE) as t1
on c.SERVICE_CODE=t1.SERVICE_CODE
inner join tablea a on a.invoice_no=t1.Invoice_No
Fiddle
Try this:
select
bcode,
case
when ccode is null then bamt
else bamt - camt
end as amt
from
(select service_code bcode, sum(amt) bamt
from b
where service_code >= 3000
group by service_code) b
left join
(select service_code ccode, sum(amt) camt
from c
where service_code >= 3000
group by service_code) c on b.bcode = c.ccode
order by bcode
Going by sample data, table b may have values for service_code that table c may not. Therefore, use a left outer join to link b and c. Also, since invoice_no does not need to appear in the output, you do not need to join to a at all.
Demo