Using Not in in SQL query - sql

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

Related

sql joining table, not providing perfect result

let me explain what i need, i have 2 table named A and B. B is sub table for A.
Here is Schema:
------------------------
Table B:
itemId version qty AId
44 1 1 200
44 1 2 201
44 2 2 200
------------------------
Table A:
id tId
200 100
201 100
------------------------
and here is what i need: i need sum of all latest version qty that have same tId.
here is my query:
select sum(qty) as sum from B
left join A on A.id=B.AId
where itemId=44 and tId=100 and
version=(select max(version) from B where itemId=44 and tId=100)
the result get wrong when one item got version 2 and version 1 ignored.
thanks.
EDIT:
what exactly i need is:
itemId version qty AId
44 2 2 200
44 1 2 201
And Result of Sum(qty) must be 4, because they have same tId and they have Max version in each AId.
Use window function.
select itemid, version, qty, aid
from (
select *, max(version) over (partition by AId) as latestVersion
from B
) as B
where version = latestVersion
to sum up
select tId, SUM(qty) AS qty_sum
from (
select *, max(version) over (partition by AId) as latestVersion
from B
) as B
join A on B.AId = A.id
where version = latestVersion
group by tId
Working solution
select b.* from B as b
inner join
(select AID,itemId,Max(version) as mVersion from B
group by AID,itemID) d
on b.AID = d.AID and b.itemID = d.itemID and b.Version = d.mVersion
inner join A as a
on B.AID = a.id
where b.itemID = 44 --apply if you need
result
itemid version qty aid
44 2 2 200
44 1 2 201
this will give you result as you sum of quantity
select itemID,sum(qty) from (
select b.* from B as b
inner join
(select AID,itemId,Max(version) as mVersion from B
group by AID,itemID) d
on b.AID = d.AID and b.itemID = d.itemID and b.Version = d.mVersion
inner join A as a
on B.AID = a.id
where b.itemID = 44 --apply if you need
) e group by itemID
result
itemid sum
44 4
Try This one
DECLARE #TA Table (id int,tid int)
DECLARE #TB Table (itemid int, version int,qty int,AID int)
INSERT INTO #TA
SELECT 200, 100
UNION ALL
SELECT 201, 100
INSERT INTO #TB
SELECT 44,1,1,201
UNION ALL
SELECT 44,1,2,200
UNION ALL
SELECT 44,2,3,200
UNION ALL
SELECT 44,2,5,201
DECLARE #tid int
SET #tid = 100
SELECT XB.* FROM #Tb XB INNER JOIN
(SELECT Version,Max(AID) Aid FROM #TA A INNER JOIN #TB B ON A.id = B.AID AND tid = #tid Group By Version) X
ON X.version = XB.version and XB.AID = X.Aid
i think this query help you to solve your problem
SELECT itemId, version, qty , AId FROM (
SELECT itemId, version, qty , AId FROM b
LEFT JOIN a ON (b.aid = a.id)
) temp
WHERE version = (SELECT MAX(version) FROM b WHERE b.aid = temp.aid)
and temp.tid = 100 and temp.itemId = 44
SELECT B.*
FROM B
INNER JOIN
(SELECT Aid,MAX(version) AS version FROM B WHERE itemId=44 GROUP BY AId) AS B1
ON B.Aid=B1.Aid
AND B.version=B1.version
INNER JOIN
(SELECT * FROM A WHERE tId=100) AS A
ON A.id=B.Aid
Order BY B.aid
For Sum of qty
SELECT SUM(B.qty)
FROM B
INNER JOIN
(SELECT Aid,MAX(version) AS version FROM B WHERE itemId=44 GROUP BY AId) AS B1
ON B.Aid=B1.Aid AND B.version=B1.version
INNER JOIN
(SELECT * FROM A WHERE tId=100) AS A
ON A.id=B.Aid
GROUP BY A.tid
Output
itemid version qty aid
44 2 2 200
44 1 2 201
Demo
http://sqlfiddle.com/#!17/092dd/5
The most efficient solution greatest-n-per-group problems in Postgres are typically using the (proprietary) operator distinct on ()
So to get the latest version for each a.id, you can use:
select distinct on (a.id) b.*
from a
join b on a.id = b.aid
order by a.id, b.version desc;
The above returns:
itemid | version | qty | aid
-------+---------+-----+----
44 | 2 | 2 | 200
44 | 1 | 2 | 201
You can then sum over the result:
select sum(qty)
from (
select distinct on (a.id) b.qty
from a
join b on a.id = b.aid
order by a.id, b.version desc
) t;
Note that normally an order by in a derived table is useless, but in this case it's needed because otherwise distinct on () wouldn't work.
Online example: http://rextester.com/DRHK19268

How to merge two particular rows into single row and reaming rows are same using stored procedure SQL Server 2012

I have data like this. first row of Id 1 from particular time period and second row of id 1 is another time period. so now want to combined id and name which are same in the two time periods reaming are same.if there is no orders from that time period its should be display 0 or null.
Id Name Qty Price
----------------------
1 Rose 4 540
1 Rose 1 640
2 Lilly 5 550
2 Lilly 18 360
3 Grand 2 460
3 Grand 10 360
4 lotus 0 0
4 Lotus 9 580
now I want data like this..
Id Name Qty Price
4 540
1 rose
1 640
5 550
2 Lilly
18 360
2 460
3 Grand
10 360
0 0
4 Lotus
9 580
This is my procedure
create PROCEDURE [dbo].[Sp_Orders]
(
#Startdate varchar(30),
#Enddate varchar(30),
#Startdate1 varchar(30),
#Enddate1 varchar(30)
)
--[Sp_Orders] '03/01/2016','03/15/2016','02/01/2016','02/28/2016'
AS
BEGIN
---First Duration----
SELECT DISTINCT
op.ProductId as id, op.Price as Prc,
sc.SubCategoryName as ScName,
COUNT(op.ProductId) AS Qty,
ROUND(SUM(op.Price * op.Quantity), 0) AS Revenue,
FROM
orderdetails od
INNER JOIN
(SELECT DISTINCT
Orderid, Productid, ProductFeatures, Price, Quantity
FROM
OrderProducts) op ON od.Orderid = op.Orderid
INNER JOIN
products p ON p.productid = op.productid
INNER JOIN
subcategory sc ON sc.subcategoryid = p.subcategoryid
WHERE
CONVERT(datetime, CONVERT(varchar(50), od.DeliveryDate, 101)) BETWEEN #Startdate AND #Enddate
GROUP BY
op.ProductID, op.Price, sc.SubCategoryName
---Second Duration----
SELECT DISTINCT
op.ProductID AS id, op.Price AS Prc,
sc.SubCategoryName AS ScName,
COUNT(op.ProductId) AS Qty,
ROUND(SUM(op.Price * op.Quantity), 0) AS Revenue,
FROM
orderdetails od
INNER JOIN
(SELECT DISTINCT
Orderid, Productid, ProductFeatures, Price, Quantity
FROM
OrderProducts) op ON od.Orderid = op.Orderid
INNER JOIN
products p ON p.productid = op.productid
INNER JOIN
subcategory sc ON sc.subcategoryid = p.subcategoryid
WHERE
CONVERT(datetime, CONVERT(varchar(50),od.DeliveryDate,101)) BETWEEN #Startdate1 AND #Enddate1
GROUP BY
op.ProductID, op.Price, sc.SubCategoryName
END
From what I understood from your Question and Comments:
Schema for your case
SELECT * INTO #TAB FROM(
SELECT 1 ID, 'ROSE' NAME, 4 QTY, 540 PRICE
UNION ALL
SELECT 1 , 'ROSE' , 1 , 640
UNION ALL
SELECT 2 , 'LILLY' , 5 , 550
UNION ALL
SELECT 2 , 'LILLY' , 18 ,360
UNION ALL
SELECT 3 , 'GRAND' , 2 , 460
UNION ALL
SELECT 3 , 'GRAND' , 10 ,360
UNION ALL
SELECT 4 , NULL,NULL,NULL
UNION ALL
SELECT 4 , 'LOTUS' , 9 , 580
) AS A
And the Logic to display is as below
SELECT CASE WHEN SNO=1 THEN CAST(ID AS VARCHAR(250)) ELSE '' END ID,
CASE WHEN SNO=1 THEN ISNULL(NAME,'') ELSE '' END NAME,ISNULL(Qty,0)Qty
,ISNuLL(Price,0)Price FROM (
SELECT ROW_NUMBER() Over(partition by Name, Id ORDER BY (SELECT 1)) SNO
,ID, NAME , Qty, Price, ID AS ID2 FROM #TAB
)AS A
ORDER BY ID2, NAME DESC
Try this from your Procedure. And may need to do type cast based on your actual datatypes
CREATE PROCEDURE [DBO].[SP_ORDERS]
(
#STARTDATE VARCHAR(30),
#ENDDATE VARCHAR(30),
#STARTDATE1 VARCHAR(30),
#ENDDATE1 VARCHAR(30)
)
--[SP_ORDERS] '03/01/2016','03/15/2016','02/01/2016','02/28/2016'
AS
BEGIN
SELECT CASE WHEN SNO=1 THEN CAST(ID AS VARCHAR(250)) ELSE '' END ID,CASE WHEN SNO=1 THEN ISNULL(SCNAME,'') ELSE '' END NAME,ISNULL(QTY,0)QTY,ISNULL(REVENUE,0)PRICE FROM (
SELECT ROW_NUMBER() OVER(PARTITION BY SCNAME, ID ORDER BY (SELECT 1)) SNO, ID, SCNAME , QTY, REVENUE, ID AS ID2 FROM (
SELECT DISTINCT OP.PRODUCTID AS ID,OP.PRICE AS PRC,SC.SUBCATEGORYNAME AS SCNAME,COUNT(OP.PRODUCTID) AS QTY, ROUND(SUM(OP.PRICE * OP.QUANTITY), 0) AS REVENUE
FROM ORDERDETAILS OD INNER JOIN
(SELECT DISTINCT ORDERID,PRODUCTID,PRODUCTFEATURES,PRICE,QUANTITY FROM ORDERPRODUCTS ) OP ON OD.ORDERID=OP.ORDERID
INNER JOIN PRODUCTS P ON P.PRODUCTID=OP.PRODUCTID
INNER JOIN SUBCATEGORY SC ON SC.SUBCATEGORYID=P.SUBCATEGORYID
WHERE CONVERT(DATETIME,CONVERT(VARCHAR(50),OD.DELIVERYDATE,101)) BETWEEN #STARTDATE AND #ENDDATE
GROUP BY OP.PRODUCTID,OP.PRICE,SC.SUBCATEGORYNAME
---SECOND DURATION----
UNION ALL --ADDED NOW
SELECT DISTINCT OP.PRODUCTID AS ID,OP.PRICE AS PRC,SC.SUBCATEGORYNAME AS SCNAME,COUNT(OP.PRODUCTID) AS QTY, ROUND(SUM(OP.PRICE * OP.QUANTITY), 0) AS REVENUE
FROM ORDERDETAILS OD INNER JOIN
(SELECT DISTINCT ORDERID,PRODUCTID,PRODUCTFEATURES,PRICE,QUANTITY FROM ORDERPRODUCTS ) OP ON OD.ORDERID=OP.ORDERID
INNER JOIN PRODUCTS P ON P.PRODUCTID=OP.PRODUCTID
INNER JOIN SUBCATEGORY SC ON SC.SUBCATEGORYID=P.SUBCATEGORYID
WHERE CONVERT(DATETIME,CONVERT(VARCHAR(50),OD.DELIVERYDATE,101)) BETWEEN #STARTDATE1 AND #ENDDATE1
GROUP BY OP.PRODUCTID,OP.PRICE,SC.SUBCATEGORYNAME
)
AS A
)B
ORDER BY ID2, NAME
END
Based on your sample data i have given this Out put but if the data is inconsistent it may not give accurate results if you see the Expected Output it gives exact same
Declare #Table1 TABLE
(Id VARCHAR(10), Name varchar(5),Qty VARCHAR(10), Price varchar(10))
;
INSERT INTO #Table1
(Id, Name,Qty, Price)
VALUES
(1, 'Rose',4, 540),
(1, 'Rose',1, 640),
(2, 'Lilly',5, 550),
(2, 'Lilly',18, 360),
(3, 'Grand',2, 460),
(3, 'Grand',10, 360),
(4,'Lotus',0,0),
(4, 'Lotus',9, 580)
;
SCRIPT
;WITH CTE AS (
Select
CASE WHEN RN = 1 THEN ID ELSE NULL END ID,
CASE WHEN RN = 1 THEN Name ELSE NULL END NAME,
Qty,
Price
from (
select
Id,
Name,
Qty,
Price,
ROW_NUMBER()OVER(PARTITION BY ID,NAME ORDER BY NAME)RN
FROM
#Table1)T)
Select CASE WHEN RN = 2 THEN T.Id ELSE '' END ID,
CASE WHEN RN = 2 THEN T.Name ELSE '' END Name,
CASE WHEN RN IN (1,3) THEN ISNULL(T.Qty,0) ELSE '' END qty,
CASE WHEN RN IN (1,3) THEN ISNULL(T.Price,0) ELSE '' END qty from (
Select
T.ID,
T.NAME,
c.Qty,
C.Price,
ROW_NUMBER()OVER(PARTITION BY T.ID,T.NAME ORDER BY T.NAME)RN
from #Table1 T
INNER JOIN CTE C
ON T.Id = C.ID
AND T.Name = C.NAME
OR (T.Qty = C.Qty OR T.Price = C.Price ))T
WHERE T.RN <> 4

SQL query Group by while using Union All

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.

only using select in sql instead of group by

I have this table:
supplier | product | qty
--------------------------
s1 | p1 | 300
s1 | p2 | 90
s2 | p3 | 89
I want to find suppliers with more than 2 products.
But only with select and where, no group by. Any suggestion?
Why would you want not to use group by is beyond me, but this might work:
SELECT Supplier FROM table outer WHERE
(
select count(Products) from table inner
where inner.Supplier = outer.Supplier
) > 2
Please bear in mind, that group by is made for stuff like that and should be used.
;WITH
sequenced_data AS
(
SELECT
supplier,
ROW_NUMBER() OVER (PARTITION BY supplier ORDER BY product) AS supplier_product_ordinal
FROM
YourTable
)
SELECT
supplier
FROM
sequenced_data
WHERE
supplier_product_ordinal = 3
But I'd expect it to be slower than using GROUP BY.
SELECT DISTINCT
supplier
FROM
yourTable
WHERE
EXISTS (SELECT * FROM yourTable AS lookup WHERE supplier = yourTable.supplier AND product < yourTable.product)
AND EXISTS (SELECT * FROM yourTable AS lookup WHERE supplier = yourTable.supplier AND product > yourTable.product);
In the usual parts and suppliers database, this relvar is named SP:
SELECT DISTINCT T1.SNO
FROM SP AS T1
JOIN SP AS T2
ON T1.SNO = T2.SNO
AND T2.PNO <> T1.PNO
JOIN SP AS T3
ON T1.SNO = T3.SNO
AND T3.PNO <> T1.PNO
AND T3.PNO <> T2.PNO;
Noting that you can use HAVING without GROUP BY:
SELECT DISTINCT T1.SNO
FROM SP AS T1
WHERE EXISTS (
SELECT 1
FROM SP AS T2
WHERE T2.SNO = T1.SNO
HAVING COUNT(*) > 2
);
;WITH T AS
(
SELECT *,
COUNT(*) OVER (PARTITION BY S) AS Cnt
FROM YourTable
)
SELECT DISTINCT S
FROM T
WHERE Cnt > 2
with subquery:
select distinct supplier
from table a
where (select count(*)
from table b
where b.supplier = a.supplier and b.product <> a.product
) > 1

Query from different tables

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