LEFT OUTER JOIN EQUIVALENT - sql

I have a tables contains null values. In ORDER table i have 2 null in PART_ID section and 2 null values in CUSTOMER_ID.
And i have that kind of query:
SELECT O.ORDER_ID , O.ORDER_DATE , O.CUST_ID, O.QUANTITY ,O.PART_ID ,
C.CUST_NAME, C.CUST_CODE, P.PART_NAME, P.PART_CODE
FROM [ORDER] O
LEFT OUTER JOIN PART P ON P.PART_ID = O.PART_ID
LEFT OUTER JOIN CUSTOMER C ON C.CUST_ID = O.CUST_ID
So here is my question. How can i do it without using outer join ?
I tried too many things including where not exists or this ;
SELECT *
FROM [ORDER] O ,CUSTOMER C, PART P
WHERE C.CUST_ID = (
SELECT CUST_ID FROM CUSTOMER C WHERE O.CUST_ID = C.CUST_ID
) AND P.PART_ID = (SELECT PART_ID FROM PART P WHERE O.PART_ID = P.PART_ID)
but i couldn't find solution. If there is a solution how it will be ?
(Note: this is homework.)
I have that kind of table :
and left outer join gives that :
the hw said do it without using outer join and get same table as left outer join gives. But like a said i coulnd't. I'm also using MSSQL.

Outer join produces super-set over inner join. Indeed, from Wikipedia: A left outer join returns all the values from an inner join plus all values in the left table that do not match to the right table.
So to model left outer join using inner join one could use UNION of inner join SELECT between same tables with same join condition and another SELECT from 1st table that returns all rows without a match from the right table (I reduced your case to a single left join):
SELECT O.ORDER_ID , O.ORDER_DATE , O.CUST_ID, O.QUANTITY ,O.PART_ID ,
P.PART_NAME, P.PART_CODE
FROM [ORDER] O JOIN PART P ON P.PART_ID = O.PART_ID
UNION
SELECT O.ORDER_ID , O.ORDER_DATE , O.CUST_ID, O.QUANTITY ,O.PART_ID ,
NULL, NULL
FROM [ORDER] O
WHERE NOT EXISTS (SELECT 'found' FROM PART P WHERE P.PART_ID = O.PART_ID)

Presumably, you want to get matches to the columns with NULL values, instead of having them fail. If so, just modify the join conditions:
FROM [ORDER] O
LEFT OUTER JOIN PART P
ON P.PART_ID = O.PART_ID or (p.Part_id is NULL and o.Part_id is null)
LEFT OUTER JOIN CUSTOMER C
ON C.CUST_ID = O.CUST_ID or (c.cust_id is null and o.cust_id is null)
The major issue with this approach is that many (most?) SQL engines will not use indexes for the join.

Is there a specific reason why you don't want to use outer join? Isn't this the result you want? :
FROM [ORDER] O
LEFT JOIN PART P
ON P.PART_ID = O.PART_ID and P.PARTID is not null
LEFT JOIN CUSTOMER C
ON C.CUST_ID = O.CUST_ID and C.CUSTID is not null

So complete answer should be like this (after my teacher gave results) :
SELECT O.ORDER_ID,O.ORDER_DATE,O.CUST_ID,
(SELECT C.CUST_CODE FROM CUSTOMER C WHERE C.CUST_ID=O.CUST_ID) AS CUST_CODE,
(SELECT C.CUST_NAME FROM CUSTOMER C WHERE C.CUST_ID=O.CUST_ID) AS CUST_NAME,
O.PART_ID,
(SELECT P.PART_CODE FROM PART P WHERE P.PART_ID = O.PART_ID ) AS PART_CODE,
(SELECT P.PART_NAME FROM PART P WHERE P.PART_ID = O.PART_ID ) AS PART_NAME,
O.QUANTITY
FROM [ORDER] O

Related

How connect two select?

I have a problem with select from two table.
I use filtr from date, when I used NOT IN but didn't work, because data to result not in second table. I want display outfits which is free in these date and outfits which not in table rent.
Structure of base in the picture:
SELECT o.Id, o.Name, c.Name, o.Description,o.Price, r.Date1, r.Date2, r.Return
FROM Outfit o INNER JOIN
Category c
ON o.Category = c.Id INNER JOIN
Rent r
ON o.Id = r.OutFit
WHERE (myfiltrdate NOT BETWEEN r.Date1 AND r.Date2) OR
r.Return IS NOT NULL
Now my result are only record/outfit which are Rent table, but I want this result and Outfit which are not in table Rent
You may try a left join -
SELECT o.Id, o.Name, c.Name, o.Description,o.Price, r.Date1, r.Date2, r.Return
FROM Outfit o LEFT JOIN
Category c
ON o.Category = c.Id INNER JOIN
Rent r
ON o.Id = r.OutFit
WHERE (myfiltrdate NOT BETWEEN r.Date1 AND r.Date2) OR
r.Return IS NULL
I think you want LEFT JOINs and filtering. Something like this:
SELECT o.Id, o.Name, c.Name, o.Description, o.Price,
r.Date1, r.Date2, r.Return
FROM Outfit o LEFT JOIN
Category c
ON o.Category = c.Id LEFT JOIN
Rent r
ON o.Id = r.OutFit AND
(myfiltrdate BETWEEN r.Date1 AND r.Date2)
WHERE r.Return IS NULL;
Change your query to left join and filter the dates like this:
SELECT o.Id, o.Name, c.Name, o.Description,o.Price, r.Date1, r.Date2, r.Return
FROM Outfit o
INNER JOIN Category c ON o.Category = c.Id
LEFT JOIN Rent r ON o.Id = r.OutFit
WHERE (myfiltrdate < r.Date1 AND myfiltrdate > r.Date2) OR
r.Return IS NOT NULL
I don't have clear if Return is a date which the outfit is returned or is a boolean but I suspect that the condition must be
And r.Return IS NOT NULL

How to obtain two values from a sub-query to be used in the where clause of sql

I have to use two values in the where clause to be tested for equality of two values obtained from a subquery. Since I am working on an existing application, I want to keep it as a subquery. The following is my query.
SELECT
o.EMAIL_ADDRESS, c.FIRST_NAME, p.PARTY_ID
FROM
ORDER o WITH (NOLOCK)
INNER JOIN
PARTY p WITH (NOLOCK) ON o.ORDER_ID = p.PARTY_ID
INNER JOIN
CUSTOMER c WITH (NOLOCK) ON p.PARTY_ID = c.CUSTOMER_ID
WHERE
(o.EMAIL_ADDRESS, c.CUSTOMER_ID) IN (SELECT EMAIL_ADDRESS, CUSTOMER_ID
FROM CUSTOMER_MASTER
WHERE insert_date > '01/02/2019')
The problem I am facing is that the first value within the where clause, o.EMAIL_ADDRESS, throws the following error:
An expression of non-boolean type specified in a context where a condition is expected
When I use a single value within the where clause it works fine.
One method is with EXISTS and a correlated subquery.
SELECT o.EMAIL_ADDRESS, c.FIRST_NAME, p.PARTY_ID
FROM ORDER_HEADER oh WITH (NOLOCK)
INNER JOIN PARTY p WITH (NOLOCK) ON o.ORDER_ID = p.PARTY_ID
INNER JOIN CUSTOMER c WITH (NOLOCK) ON p.PARTY_ID = c.CUSTOMER_ID
WHERE EXISTS(
SELECT 1
FROM CUSTOMER_MASTER AS cm
WHERE cm.insert_date > '01/02/2019'
AND o.EMAIL_ADDRESS = cm.EMAIL_ADDRESS
AND c.CUSTOMER_ID = cm.c.CUSTOMER_ID
);
in allows single column list only. So create single column.
SELECT o.EMAIL_ADDRESS, c.FIRST_NAME, p.PARTY_ID
FROM ORDER o WITH (NOLOCK)
INNER JOIN PARTY p WITH (NOLOCK) ON o.ORDER_ID = p.PARTY_ID
INNER JOIN CUSTOMER c WITH (NOLOCK) ON p.PARTY_ID = c.CUSTOMER_ID
WHERE o.EMAIL_ADDRESS + cast(c.CUSTOMER_ID as varchar)
IN (select EMAIL_ADDRESS + cast(CUSTOMER_ID as varchar)
from CUSTOMER_MASTER where insert_date > '01/02/2019')
Use EXISTS. I would also advise fixing the date format:
SELECT o.EMAIL_ADDRESS, c.FIRST_NAME, p.PARTY_ID
FROM ORDER o JOIN
PARTY p
ON o.ORDER_ID = p.PARTY_ID JOIN
CUSTOMER c
ON p.PARTY_ID = c.CUSTOMER_ID
WHERE EXISTS (SELECT 1
FROM CUSTOMER_MASTER cm
WHERE cm.EMAIL_ADDRESS = o.EMAIL_ADDRESS AND
cm.CUSTOMER_ID = c.CUSTOMER_ID AND
cm.insert_date > '2019-02-01'
);
Your date constants should be in the YYYYMMDD format.
Based on your logic, though, I don't think you need all the JOINs:
SELECT o.EMAIL_ADDRESS, c.FIRST_NAME, o.ORDER_ID
FROM ORDER o JOIN
CUSTOMER c
ON o.ORDER_ID = c.CUSTOMER_ID
WHERE EXISTS (SELECT 1
FROM CUSTOMER_MASTER cm
WHERE cm.EMAIL_ADDRESS = o.EMAIL_ADDRESS AND
cm.CUSTOMER_ID = c.CUSTOMER_ID AND
cm.insert_date > '2019-02-01'
);
The table PARTY doesn't seem necessary, because the orders can align directly to the customers.

Select every value (even when it is null) with inner join sql

This is my sql select statment
SELECT k.name, c.name AS nameCustomer, o.*
FROM offertes o
INNER JOIN customers k
ON o.idCustomer= k.id
INNER JOIN contactperson c
ON o.idContact = c.id;
When o.idContact doesn't exist, then there will be no values selected. I wan't to get NULL instead of nothing. It still need to SELECT the whole row! Can anyone help me?
ps. I think it's going wrong with the inner join (ON o.idContact = c.id);
Try this:
Replace your last INNER JOIN with LEFT JOIN.
Using LEFT JOIN you tell my main table (offertes) returns always result but if in secondary table (contactperson) there's no row matches returns NULL all fields of that table
SELECT k.name, c.name AS nameCustomer, o.*
FROM offertes o
INNER JOIN customers k
ON o.idCustomer= k.id
LEFT JOIN contactperson c
ON o.idContact = c.id;
You'll need an outer join instead.
e.g.
SELECT k.name, c.name AS nameCustomer, o.*
FROM customers k LEFT OUTER JOIN
(offertes o INNER JOIN
contactperson c
ON o.idContact = c.id)
ON o.idCustomer= k.id;
(I assume there'll be a counterpart of an offerte in contactperson, else you'll need an outer join there as well)
you need to rewrite a query using outer join
SELECT k.name, c.name AS nameCustomer, o.*
FROM customers k
LEFT OUTER JOIN offertes o ON o.idCustomer = k.id
LEFT OUTER JOIN contactperson c ON o.idContact = c.id;

Left join without using left join with 3 tables

I have to get all data from 3 tables with left join. I did that with and without using left join. But my teacher ask another solution that uses just inner join. I just couldn't find the solution please give some advice. Here are the tables:
And the results should look like this:
With left join solution:
SELECT O.*,C.CUST_CODE,C.CUST_NAME,P.PART_CODE,P.PART_NAME
FROM ORDERS O
LEFT OUTER JOIN PART P ON P.PART_ID = O.PART_ID
LEFT OUTER JOIN CUSTOMER C ON C.CUST_ID = O.CUST_ID
Without left join solution:
SELECT O.*,
(SELECT C.CUST_CODE FROM CUSTOMER C WHERE C.CUST_ID=O.CUST_ID) AS CUST_CODE,
(SELECT C.CUST_NAME FROM CUSTOMER C WHERE C.CUST_ID=O.CUST_ID) AS CUST_NAME,
(SELECT P.PART_CODE FROM PART P WHERE P.PART_ID = O.PART_ID ) AS PART_CODE,
(SELECT P.PART_NAME FROM PART P WHERE P.PART_ID = O.PART_ID ) AS PART_NAME
FROM ORDERS O
Here is one approach which uses only INNER JOIN and does not use LEFT JOIN anywhere. It begins with your original query using INNER JOIN instead of LEFT JOIN, and then adds to that result set the pieces which are missing from taking the inner product of all the tables.
SELECT t.* FROM
(
SELECT O.ORDER_ID, O.ORDER_DATE, C.CUST_CODE, C.CUST_NAME, P.PART_CODE, P.PART_NAME
FROM ORDERS O
INNER JOIN PART P
ON P.PART_ID = O.PART_ID
INNER JOIN CUSTOMER C
ON C.CUST_ID = O.CUST_ID
UNION
SELECT O.ORDER_ID, O.ORDER_DATE, NULL AS CUST_CODE, NULL AS CUST_NAME, P.PART_CODE,
P.PART_NAME
FROM ORDERS O
INNER JOIN PART P
ON P.PART_ID = O.PART_ID
WHERE O.CUST_ID NOT IN (SELECT C.CUST_ID FROM CUSTOMER C)
OR O.CUST_ID IS NULL
UNION
SELECT O.ORDER_ID, O.ORDER_DATE, C.CUST_CODE, C.CUST_NAME, NULL AS PART_CODE,
NULL AS PART_NAME
FROM ORDERS O
INNER JOIN CUSTOMER C
ON C.CUST_ID = O.CUST_ID
WHERE O.PART_ID NOT IN (SELECT P.PART_ID FROM PART P)
OR O.PART_ID IS NULL
UNION
SELECT O.ORDER_ID, O.ORDER_DATE, NULL AS CUST_CODE, NULL AS CUST_NAME,
NULL AS PART_CODE, NULL AS PART_NAME
FROM ORDERS O
WHERE (O.CUST_ID NOT IN (SELECT C.CUST_ID FROM CUSTOMER C) AND
O.PART_ID NOT IN (SELECT P.PART_ID FROM PART P)) OR
(O.CUST_ID IS NULL AND O.PART_ID IS NULL)
) t
ORDER BY t.ORDER_ID ASC
Follow the link below for a working demo:
SQLFiddle
This makes no sense in "real life", but I understand it's meaningfulness in a SQL course. You have a good teacher.
Try like this
SELECT * FROM
(
SELECT O.*,C.CUST_CODE,C.CUST_NAME,P.PART_CODE,P.PART_NAME
FROM ORDERS O
INNER JOIN PART P ON P.PART_ID = O.PART_ID
INNER JOIN CUSTOMER C ON C.CUST_ID = O.CUST_ID
UNION
SELECT O.*,NULL,NULL,P.PART_CODE,P.PART_NAME
FROM ORDERS O
INNER JOIN PART P ON P.PART_ID = O.PART_ID
WHERE O.CUST_ID IS NULL
UNION
SELECT O.*,C.CUST_CODE,C.CUST_NAME,NULL, NULL
FROM ORDERS O
INNER JOIN CUSTOMER C ON C.CUST_ID = O.CUST_ID
WHERE O.PART_ID IS NULL
UNION
SELECT O.*,NULL,NULL,NULL, NULL
FROM ORDERS O
WHERE O.PART_ID IS NULL AND O.CUST_ID IS NULL
) T
ORDER BY ORDER_ID

INNER JOIN Distinct ID

I have the following code:
FROM CTE_Order cte
INNER JOIN tblOrders o
ON cte.OrderId = o.Id
INNER JOIN tblOrderUnits ou
ON o.id = ou.OrderId
INNER JOIN tblOrderServiceUnits osu
ON ou.VMSUnitID = osu.UnitId
When I join the ou I get 2 of the same unit Id's. This make the Inner Join tblOrderServiceUnits return 4 rows with 2 being duplicates. I need it to only return the 2 rows the are different. How do I use a distinct to Inner Join only distinct ou.id?
Sorry for the bad explanation but basically I am jsut trying to see how an INNER JOIN with a distinct subquery would work, If someone could give me an example of that I could figure it out from there.
INNER JOIN (SELECT DISTINCT * FROM X) Alias
ON Alias.ID = Primary.ID
For your example:
INNER JOIN (SELECT DISTINCT VMSUnitID, OrderId FROM tblOrderUnits) ou
ON o.id = ou.OrderId