Filter Left join sql - 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

Related

SQL INNER JOIN using CASE and 3 tables

I have the following tables and want show only the types that are available, while counting the products in that category.
Types
Type_Id
Name
1
Candy
2
Chocolate Bar
Products
Product_Id
Name
Type_Id
AvailabilityId
1
Chocolate Name 1
1
1
2
Chcoolate Name 1
2
2
3
Candy Name 1
2
2
Availability
Availability_Id
Name
1
Available
2
Reserved
3
Sol d
Desired Result
Type_Id
Name
TotalAvailable
1
Candy
1
2
Chocolate
2
Start with a basic JOIN between all three tables, on the related columns. Note use of table aliases t - Types, p - Products, a - Availability
SELECT *
FROM Types t
INNER JOIN Products p ON p.Type_Id = t.Type_Id
INNER JOIN Availability a ON a.Availability_Id = p.Availability_Id
Next add a WHERE clause to filter results by the availability status:
SELECT *
FROM Types t
INNER JOIN Products p ON p.Type_Id = t.Type_Id
INNER JOIN Availability a ON a.Availability_Id = p.Availability_Id
WHERE a.Name IN ('Available', 'Reserved')
Results:
Type_Id | Name | Product_Id | Name | Type_Id | Availability_Id | Availability_Id | Name
------: | :------------ | ---------: | :------------- | ------: | --------------: | --------------: | :--------
1 | Candy | 1 | Chocolate Name | 1 | 1 | 1 | Available
2 | Chocolate Bar | 2 | Chcoolate Name | 2 | 2 | 2 | Reserved
2 | Chocolate Bar | 3 | Candy Name | 2 | 2 | 2 | Reserved
Finally COUNT(*) the total rows matched, grouping by category (i.e. [Type].[Name])
SELECT t.Type_Id
, t.Name AS Type_Name
, COUNT(*) AS Total_Products
FROM Types t
INNER JOIN Products p ON p.Type_Id = t.Type_Id
INNER JOIN Availability a ON a.Availability_Id = p.Availability_Id
WHERE a.Name IN ('Available', 'Reserved')
GROUP BY t.Type_Id
, t.Name
Type_Id | Type_Name | Total_Products
------: | :------------ | -------------:
1 | Candy | 1
2 | Chocolate Bar | 2
SQL Fiddle
You can use an inner query with inner join to achieve this. Here's a SQL fiddle: http://sqlfiddle.com/#!9/42bd7f/2

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

Select Customers where not have value in other table with join

I need to select all Customers from the table Customer where Value in table Customer_Value is not 4.
Customers:
+------------+-------+
| Customer | ... |
+------------+-------+
| 312 | ... |
| 345 | ... |
| 678 | ... |
+------------+-------+
Customer_Value:
+------------+-------+
| Customer | Value |
+------------+-------+
| 312 | 1 |
| 312 | 2 |
| 345 | 1 |
| 345 | 2 |
| 345 | 3 |
| 678 | 1 |
| 678 | 2 |
| 678 | 4 |
+------------+-------+
To get my result I've used the following query:
SELECT C.Customer FROM [Customer] C
Left join Customer_Value V ON (C.Customer = V.Customer)
WHERE C.Customer NOT IN (SELECT Customer FROM [Customer_Value] WHERE Value = '4')
GROUP BY C.Customer
So my question is:
Is that a fast and good query? Or are there some other better solutions to get all the Customer Ids?
You can avoid Negative condition using Left Join and IS NULL Filter in where Condition.
SELECT C.Customer FROM [Customer] C
Left join Customer_Value V ON (C.Customer = V.Customer) and V.Value = '4'
WHERE V.Value is null
GROUP BY C.Customer
Your method is overkill; the JOIN is not necessary. I would use not exists:
select c.Customer
from Customer c
where not exists (select 1
from customer_value cv
where c.Customer = v.Customer and
cv.value = 4
);
You can also use aggregation, if you assume that all customers have at least one row in customer_value:
select cv.customer
from customer_value cv
group by cv.customer
having sum(case when cv.value = 4 then 1 else 0 end) = 0;
I would do
select * from customer c
join (
select distinct customer from customer_value where value!=4) v on c.customer = v.customer

Select query INNER JOIN issue

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
)

Is it possible to select multiple conditional counts across three tables in a single SQL query?

My SQL-fu is too weak for this, and I'm not even sure it's possible in a single SQL call.
Given I have the following tables:
PARTNER
+----+--------+
| id | name |
+----+--------+
| 1 | bloggs |
| 2 | jones |
PARTNER MANAGER
+----+--------------+------+
| id | partner_id | name |
+----+--------------+------+
| 1 | 1 | fred |
| 2 | 2 | dave |
COMPANY
+----+--------------------+--------+----------+
| id | partner_manager_id | name | active |
+----+--------------------+--------+----------+
| 1 | 1 | comp1 | true |
| 2 | 1 | comp2 | false |
| 3 | 2 | comp3 | true |
| 4 | 2 | comp4 | true |
| 5 | 2 | comp5 | true |
| 6 | 2 | comp6 | true |
I'd like to output the following in a single SQL call:
+--------------+--------------------+----------------------+
| partner_name | n_active_companies | n_inactive_companies |
+--------------+--------------------+----------------------+
| bloggs | 1 | 1 |
| jones | 4 | 0 |
I can join the three tables using two LEFT JOINs but how I can aggregate the counts (with or without the WHERE clause) is eluding me.
Am I barking up the wrong tree, so to speak?
This gets you most of the way there:
SELECT
partner_manager_id,
SUM(CASE WHEN active THEN 1 ELSE 0 END) AS n_active_companies,
SUM(CASE WHEN active THEN 0 ELSE 1 END) AS n_inactive_companies
FROM COMPANY
GROUP BY partner_manager_id
The rest of your question is basically asking how to join this result to the remaining tables. As you point out, to do this use JOINs.
SELECT
PARTNER.name,
T1.n_active_companies,
T1.n_inactive_companies
FROM
PARTNER
LEFT JOIN PARTNER_MANAGER ON partner_id = PARTNER.id
LEFT JOIN
(
SELECT
partner_manager_id,
SUM(CASE WHEN active THEN 1 ELSE 0 END) AS n_active_companies,
SUM(CASE WHEN active THEN 0 ELSE 1 END) AS n_inactive_companies
FROM COMPANY
GROUP BY partner_manager_id
) T1
ON T1.partner_manager_id = PARTNER_MANAGER.id
select p.name "Partner Name"
, c1.cnt "n_active_companies"
, c2.cnt "n_inactive_companies"
from partner p
, (select partner_manager_id id, count(partner_manager_id) cnt from company where active = 'true' group by partner_manager_id) c1
, (select partner_manager_id id, count(partner_manager_id) cnt from company where active = 'false' group by partner_manager_id) c2
where c1.id = p.id
and c2.id = p.id
select p.name as 'partner_name',
sum(case when active then 1 else 0) as 'n_active_companies',
sum(case when active then 0 else 1) as 'n_inactive_companies'
from COMPANY c
join PARTNER_MANAGER pm on c.partner_manager_id = pm.id
join PARTNER p on pm.partner_id = p.id
group by p.name