Select query INNER JOIN issue - sql

I have tow tables Requisitions and RequisitionDetails
Requisitions table
+---------------+-----------------+
| RequisitionID | RequisitionDate |
+---------------+-----------------+
| 1 | 2016-08-17 |
| 2 | 2016-08-18 |
| 3 | 2016-08-19 |
+---------------+-----------------+
RequisitionDetails table
+---------------------+---------------+--------+----------+------------------+
| RequisitionDetailID | RequisitionID | ItemID | Quantity | ReceivedQuantity |
+---------------------+---------------+--------+----------+------------------+
| 1 | 1 | 1 | 2 | 1 |
| 2 | 1 | 2 | 3 | 2 |
| 3 | 2 | 3 | 4 | 3 |
+---------------------+---------------+--------+----------+------------------+
I am trying to get Requisition data where Quantity is not equal to ReceivedQuantity.
i have tried the below query but its record with RequisitionID 1 twice.
How can i make the query returns the Requisition data without repeating the requisition data based on items that have Quantity is not equal to ReceivedQuantity.
SELECT
dbo.Requisitions.RequisitionID,
dbo.Requisitions.RequisitionDate
FROM dbo.Requisitions
INNER JOIN dbo.RequisitionDetails
ON dbo.Requisitions.RequisitionID = dbo.RequisitionDetails.RequisitionID
where dbo.RequisitionDetails.Quantity != dbo.RequisitionDetails.ReceivedQuantity

It's returning twice because of the two rows with RequistionID = 1 in the RequistionDetails table. Since the rows returned are exact duplicates you can simply add the DISTINCT keyword to your select to see one of them:
SELECT DISTINCT
dbo.Requisitions.RequisitionID,
dbo.Requisitions.RequisitionDate
FROM dbo.Requisitions
INNER JOIN dbo.RequisitionDetails
ON dbo.Requisitions.RequisitionID = dbo.RequisitionDetails.RequisitionID
where dbo.RequisitionDetails.Quantity!=
dbo.RequisitionDetails.ReceivedQuantity
You should also use some aliases to clean up your query:
SELECT DISTINCT
R.RequisitionID,
R.RequisitionDate
FROM dbo.Requisitions R
INNER JOIN dbo.RequisitionDetails RD ON R.RequisitionID = RD.RequisitionID
WHERE RD.Quantity != RD.ReceivedQuantity

You also can use exists for your case
select
* from requistions rq where exists(
select 1 from RequisitionDetails rd where rd.RequisitionID=rq.RequisitionID
and rd.Quantity!=rd.ReceivedQuantity)

As you don't need columns from the 2nd table you can also switch to EXISTS to avoid DISTINCT:
SELECT req.*
FROM dbo.Requisitions as req
WHERE EXISTS
( SELECT * FROM dbo.RequisitionDetails as req_det
WHERE req.RequisitionID = req_det.RequisitionID
AND Quantity <> ReceivedQuantity
)
Or IN:
SELECT req.*
FROM dbo.Requisitions
WHERE RequisitionID IN
( SELECT RequisitionID
FROM dbo.RequisitionDetails
WHERE Quantity <> ReceivedQuantity
)

Related

Left join with left table values with select query

I want a query where I can show the left table value with in select query.
Basically Left column have column A having same value but column B having different values so group_concat the column b value in the left table.
In the below query I am getting title of each in a separate row but I want it in same row against the commerce_order_item.order_id because commerce_order_item.order_id containe same value so want to group_concat(commerce_order_item.title)
SELECT commerce_order.order_id, commerce_order.mail, commerce_order.total_price__number, commerce_order.changed, commerce_order_item.title FROM commerce_order LEFT JOIN commerce_order_item ON commerce_order.order_id = commerce_order_item.order_id WHERE cart = 1 AND commerce_order.changed BETWEEN $startdate AND $endates
Below is the query to group_concat
SELECT order_id, GROUP_CONCAT(title) FROM commerce_order_item GROUP BY order_id;
Resultant query
SELECT commerce_order.order_id, commerce_order.mail, commerce_order.total_price__number, commerce_order.changed, commerce_order_item.title FROM commerce_order LEFT JOIN commerce_order_item ON commerce_order.order_id = commerce_order_item.order_id WHERE cart = 1 AND commerce_order.changed BETWEEN 1640998861 AND 1641258061 AND commerce_order_item.title = (SELECT GROUP_CONCAT(commerce_order_item.title) FROM commerce_order_item GROUP BY commerce_order_item.order_id)
Here are sample table:
commerce_order
commerce_order tabe as below
+--------+---------------+--------------+-----------+
|order_id| mail| | Total Price | changed |
+--------+---------------+------+-------+-----------+
| 1 |abc#gmail.com | 1000 |1641276265 |
| 2 |abc1#gmail.com | 5000 |1641276266 |
| 3 |abc2#gmail.com | 100 |1641276267 |
| 4 |abc3#gmail.com | 1001 |1641276268 |
| 5 |abc4#gmail.com | 10000 |1641276269 |
commerce_order_item table as below
+--------+-------+
|order_id| title |
+--------+-------+
| 1 | abc |
| 1 | xyz |
| 1 | def |
| 2 | ghi |
| 2 | lmn |
Result should be:
Order Id | Mail | total Price | Time(timestamp)| title
1 abc#gmail.com 1000 1641276265 abc,xyz,def
2 abc1#gmail1.com 5000 1641276266 ghi,lmn
Does this not give you what you want?
SELECT commerce_order.order_id
, commerce_order.mail
, commerce_order.total_price__number
, commerce_order.changed
, GROUP_CONCAT(commerce_order_item.title)
FROM commerce_order
LEFT JOIN commerce_order_item ON commerce_order.order_id = commerce_order_item.order_id
WHERE cart = 1
AND commerce_order.changed BETWEEN 1640998861 AND 1641258061
GROUP BY commerce_order.order_id
, commerce_order.mail
, commerce_order.total_price__number
, commerce_order.changed

SQL left join with latest record

I want to left join a table with the latest record only.
I have Customer1 table:
+--------+----------+
| CustID | CustName |
+--------+----------+
| 1 | ABC123 |
| 2 | 456XYZ |
| 3 | 5PQR3 |
| 4 | 789XYZ |
| 5 | 789A |
+--------+----------+
SalesInvoice table:
+------------+--------+-----------+
| InvDate | CustID | InvNumber |
+------------+--------+-----------+
| 2020-03-01 | 1 | IV236 |
| 2020-04-07 | 1 | IV644 |
| 2020-06-13 | 2 | IV869 |
| 2020-03-29 | 3 | IV436 |
| 2020-02-06 | 3 | IV126 |
+------------+--------+-----------+
And I want this required output:
+--------+------------+-----------+
| CustID | InvDate | InvNumber |
+--------+------------+-----------+
| 1 | 2020-04-07 | IV644 |
| 2 | 2020-06-13 | IV869 |
| 3 | 2020-03-29 | IV436 |
| 4 | | |
| 5 | | |
+--------+------------+-----------+
For quick and easy, below is the sample code.
drop table if exists #Customer1
create table #Customer1(CustID int, CustName varchar (100))
insert into #Customer1 values
(1,'ABC123'),
(2,'456XYZ'),
(3,'5PQR3'),
(4,'789XYZ'),
(5,'789A')
drop table if exists #SalesInvoice
create table #SalesInvoice(InvDate DATE, CustID INT, InvNumber varchar (100))
insert into #SalesInvoice values
('2020-03-01',1,'IV236'),
('2020-04-07',1,'IV644'),
('2020-06-13',2,'IV869'),
('2020-03-29',3,'IV436'),
('2020-02-06',3,'IV126')
I like using TOP 1 WITH TIES in this case:
SELECT TOP 1 WITH TIES c.CustID, i.InvDate, i.InvNumber
FROM #Customer1 c
LEFT JOIN #Invoices i ON c.CustID = i.CustID
ORDER BY ROW_NUMBER() OVER (PARTITION BY c.CustID ORDER BY i.InvDate DESC);
Demo
The top 1 trick here is to order by row number, assigning a sequence to each customer, with the sequence descending by invoice date. Then, this approach retains just the most recent invoice record for each customer.
I recommend outer apply:
select c.*, i.*
from #c c outer apply
(select top (1) i.*
from #invoices i
where i.custId = c.custId
order by i.invDate desc
) i;
outer apply implements a special type of join called a "lateral join". This is a very powerful construct. But when learning about them, you can think of a lateral join as a correlated subquery that can return more than one column and more than one row.
You can try ROW_NUMBER window function instead of lateral joins with this simple self-explaining T-SQL
SELECT c.CustID
, d.InvDate
, d.InvNumber
FROM #C c
LEFT JOIN (
SELECT *
, ROW_NUMBER() OVER (PARTITION BY CustID ORDER BY InvDate DESC) AS RowNo
FROM #D
) d
ON c.CustID = d.CustID
AND d.RowNo = 1
Basically ROW_NUMBER is used to filter the "last" invoice in one table scan, instead of performing SELECT TOP 1 ... ORDER BY in the correlated query which has to be executed multiple times -- as much as the number of customers.

SQL - IN clause with no match

I'm trying to build a query where I can select from a table all products with a certain ID but I would also like to find out what products were not found within the IN clause.
Product Table
ID | Name
---|---------
1 | ProductA
2 | ProductB
4 | ProductD
5 | ProductE
6 | ProductF
7 | ProductG
select *
from products
where id in (2,3,7);
As you can see, product id 3 does not exist in the table.
My query will only return rows 2 and 7.
I would like a blank/null row returned if a value in the IN clause did not return anything.
Desired Results:
ID | Name
---|---------
2 | ProductB
3 | null
7 | ProductG
You can use a left join:
select i.id, p.name
from (select 2 as id union all select 3 union all select 7
) i left join
products p
on p.id = i.id
IN is not useful in this case.
Use a CTE with the ids that you want to search for and left join to the table:
with cte(id) as (select * from (values (2),(3),(7)))
select c.id, p.name
from cte c left join products p
on p.id = c.id
See the demo.
Results:
| id | Name |
| --- | -------- |
| 2 | ProductB |
| 3 | |
| 7 | ProductG |

SQL Find all rows with foreign key 1 when any of foreign key 2 appear in second table

I'm up against the limit of my query writing expertise.
I have the following table in which the combination of extid + extdt us a sort of compound key:
ents
entid | extid | extdt | itemid |
=======================================
1000 | 100 | '2016-08-01' | 1 |
1001 | 100 | '2016-08-01' | 2 |
1002 | 200 | '2016-08-01' | 3 |
1003 | 100 | '2016-08-02' | 4 |
1004 | 200 | '2016-08-02' | 5 |
1005 | 100 | '2016-08-02' | 6 |
So if itemid (1 or 2)are in the items table, the query will return both row 1000 and 1001. If itemid 3 exists, row 1002 is returned and so on...
items
itemid | itemDesc |
===================
1 | 'fu' |
3 | 'bar' |
4 | 'blah' |
With the above items table, I would expect to get back :
entid | extid | extdt | itemid |
=======================================
1000 | 100 | '2016-08-01' | 1 |
1001 | 100 | '2016-08-01' | 2 |
1002 | 200 | '2016-08-01' | 3 |
1003 | 100 | '2016-08-02' | 4 |
1005 | 100 | '2016-08-02' | 6 |
I can't think of an aggregate function that would do what I'm looking for, nor does it seem like ANY/EXISTS would work. I'm getting hung up on the grouping the itemids... Could anyone please point me in the right direction?
First you need get the composite keys matching your items, but include DISTINCT to avoid duplicates
SELECT DISTINCT extid, extdt
FROM ents
JOIN items
ON ents.itemid = items.itemid
Now you retrive every row matching the selected composite key
SELECT *
FROM ents
JOIN ( SELECT DISTINCT extid, extdt
FROM ents
JOIN items
ON ents.itemid = items.itemid
) comp_key
ON ents.extid = comp_key.extid
AND ents.extdt = comp_key.extdt
select *
from ents e1
where e1.extid in
(select extid
from ents e2
where e2.itemid in (select itemid from items))
Maybe? You could also modify the last inner query for the item ids you specificly want.
Just join em up based on the logic
SELECT e.*
-- records from the ents table
FROM ents e
-- with an extid that matches
JOIN ents extid on e.extid = extid.extid
-- all the records with an itemid in the items table.
JOIN items i on extid.itemid = i.itemid
if the unique key is id and date then use
JOIN ents extid on e.extid = extid.extid and e.extdt = extid.extdt
From your description (but not the example, which seems to contradict it):
SELECT e.*
FROM item i
JOIN ent e ON e.itemid = i.itemid
But I suspect the problem isn't that simple?
SELECT e.*
FROM [Test].[dbo].[ents] e,[Test].[dbo].[items] i
WHERE e.extid in (SELECT extid from [Test].[dbo].[ents] oe where oe.itemid=i.itemid)
and e.extdt in (SELECT extdt from [Test].[dbo].[ents] oe where oe.itemid=i.itemid)
order by itemid

Filter Left join sql

I have this sql query :
SELECT Customer.IDCustomer, Customer.Name,
Sign.IdSign, Sign.Name, Sign.Delete
FROM Customer
LEFT JOIN Sign_Customer ON Sign_Customer.IDCustomer=Customer.IDCustomer
AND ( SELECT CAST(CASE WHEN S_C.Delete=0 OR S_C.Delete is Null THEN 1 ELSE 0 END AS BIT )
FROM Sign AS S_C
WHERE S_C.IdSign=Sign_Customer.IdSign)=1
LEFT JOIN Sign ON Sign.IdSign=Sign_Customer.IdSign
ORDER BY Customer.Name
This query works fine, but I want to know if it exists another way to filter my first left join without use the SELECT CAST... condition.
Update
Sorry, I don't explain what I want in my result:
All my customer without Sign
All my customer whith enable Sign
A Customer with disable Sign doesn't appear or appear like a "without Sign" if no enable Sign exist for it.
Exemple:
my customer table
IDCustomer | Name
1 | Customer 1
2 | Customer 2
3 | Customer 3
4 | Customer 4
Sign_Customer:
IDCustomer | IdSign
1 | 1
3 | 2
3 | 3
3 | 5
4 | 4
Sign
IdSign | Name | Delete
1 | Sign1 | 0
2 | Sign2 | 1
3 | Sign3 | 0
4 | Sign4 | 1
5 | Sign5 | 0
Result
Customer.IDCustomer | Customer.Name | Sign.IdSign | Sign.Name | Sign.Delete
1 | Customer 1 | 1 | Sign1 | 0
2 | Customer 2 | null | null | null
3 | Customer 3 | 3 | Sign3 | 0
3 | Customer 3 | 5 | Sign5 | 0
4 | Customer 4 | null | null | null
How about the following?
SELECT Customer.IDCustomer
, Customer.Name
, Sign.IdSign
, Sign.Name
, Sign.Delete
FROM Customer
LEFT JOIN Sign_Customer
JOIN Sign
ON Sign_Customer.IdSign = Sign.IdSign
AND Sign.Delete = 0
ON Customer.IDCustomer = Sign_Customer.IDCustomer
ORDER BY Customer.NAME;
SELECT Customer.IDCustomer, Customer.Name, Sign.IdSign, Sign.LibEnseigne, Sign.Delete
FROM Customer
LEFT JOIN Sign_Customer ON Sign_Customer.IDCustomer=Customer.IDCustomer
LEFT JOIN Sign ON Sign.IdSign=Sign_Customer.IdSign
AND (S_C.Delete=0 OR S_C.Delete is Null)
ORDER BY TEnseigne.NomEnseigne, Customer.Name
I believe this meets your criteria:
SELECT Customer.IDCustomer, Customer.Name,
Sign.IdSign, Sign.Name, Sign.Delete
FROM Customer
LEFT JOIN (
select Sign_Customer.*
from Sign_Customer
join Sign on S_C.IdSign=Sign_Customer.IdSign
where isnull(S_C.Delete,0) = 0
) Sign_Customer ON Sign_Customer.IDCustomer=Customer.IDCustomer
LEFT JOIN Sign ON Sign.IdSign=Sign_Customer.IdSign
ORDER BY Customer.Name