Joining several tables and views - sql

SELECT dbo.Monitor_Request.WorkDesc
, dbo.Monitor_Request.Request_ID
, dbo.Monitor_Request.Due_Dt
, dbo.Monitor_Request.Attempts
, dbo.Monitor_Request.Status_Ind
, dbo.Monitor_Request.Create_Dt
, dbo.Monitor_Request.Monitor_ID
, dbo.Monitor_Request.ByCustomer_ID
, dbo.Monitor_Request.ByCompanyID
, dbo.CompanyShim.Company_Name
, dbo.PostalAddressShim.HouseName
, dbo.PostalAddressShim.Street
, dbo.PostalAddressShim.Town
, dbo.PostalAddressShim.City
, dbo.PostalAddressShim.County
, dbo.PostalAddressShim.Postcode
FROM dbo.PostalAddressShim
RIGHT OUTER JOIN dbo.CompanyShim ON dbo.PostalAddressShim.Address_ID = dbo.CompanyShim.Company_Address_ID
RIGHT OUTER JOIN dbo.CUSTOMER ON dbo.PostalAddressShim.Address_ID = dbo.CUSTOMER.Address_ID
RIGHT OUTER JOIN dbo.Monitor_Request ON dbo.CUSTOMER.Customer_ID = dbo.Monitor_Request.ByCustomer_ID
AND dbo.CompanyShim.Company_ID = dbo.Monitor_Request.ByCompanyID
I have created a view to display customer details with their addresses. A customer can be an individual or a company. They are stored in in different tables. For individuals the details are stored in a table called Customer and the company details are stored in the Company table. I am trying to create a view of all the customers in the database to display their addresses. When I join the tables separately I am getting the address details but if I am joining both the tables(Customer and Company) at once I am not getting null values for address details columns.
How can I get all the address details of the customers (Individual or company) from the database

I rarely found a need to use RIGHT OUTER JOIN and every time I encounter it, it forces me to think from right to left complicating things.
If I didn't goof up to badly, following joins should be equivalent to what you have written
SQL Statement
dbo.Monitor_Request mr
LEFT OUTER JOIN dbo.Customer c ON c.Customer_ID = mr.ByCustomerID
LEFT OUTER JOIN dbo.CompanyShim cs ON cs.Company_ID = mr.ByCompanyID
LEFT OUTER JOIN dbo.PostalAddressShim pas ON pas.Address_ID = c.Address_ID
AND pas.Address_ID = cs.Company_Address_ID
Now this is something I can read and theorize about. What's immediate obvious from this statement is the AND clause in joining the adresses with customers and companies effectively negating each other and returning no adresses at all.
My guess is you should simply
replace your RIGHT JOINS with LEFT JOINS
use OR instead of AND
SQL Statement
dbo.Monitor_Request mr
LEFT OUTER JOIN dbo.Customer c ON c.Customer_ID = mr.ByCustomerID
LEFT OUTER JOIN dbo.CompanyShim cs ON cs.Company_ID = mr.ByCompanyID
LEFT OUTER JOIN dbo.PostalAddressShim pas ON pas.Address_ID = c.Address_ID
OR pas.Address_ID = cs.Company_Address_ID

At first glance, try changing your RIGHT OUTER JOINs to LEFT OUTER JOINs.

Related

Is it possible to have multiple joins between two tables in stored procedure?

I have two tables, "Booking" and "City". CityName field is primary key in City table and I have used it as foreign key for two columns "SourceCity" and "DestinationCity" in Booking table. I want to create a stored procedure to select all existing data from the Booking table for creating a view list, for which I have written the following.
SELECT [dbo].[Booking].[BookingID],
[dbo].[Booking].[CustomerName],
[dbo].[City].[CityName],
[dbo].[City].[CityName],
[dbo].[Booking].[StartingDate],
[dbo].[Booking].[EndingDate],
[dbo].[Car].[LicensePlateNumber],
[dbo].[Driver].[DriverName],
[dbo].[Booking].[AdvanceTaken],
[dbo].[Booking].[PendingPayment],
[dbo].[Booking].[TotalRent],
[dbo].[Booking].[BookingDate],
[dbo].[Booking].[IDProof]
FROM [dbo].[Booking]
**LEFT OUTER JOIN [dbo].[City]
ON [dbo].[Booking].[SourceCity] = [dbo].[City].[CityName]
AND [dbo].[Booking].[DestinationCity] = [dbo].[City].[CityName]**
LEFT OUTER JOIN [dbo].[Driver]
ON [dbo].[Driver].[DriverID] = [dbo].[Booking].[DriverAllotted]
LEFT OUTER JOIN [dbo].[Car]
ON [dbo].[Car].[CarID] = [dbo].[Booking].[CarAllotted]
ORDER BY [dbo].[Booking].[BookingID]
I am not sure if it is possible to do the following
LEFT OUTER JOIN [dbo].[City]
ON [dbo].[Booking].[SourceCity] = [dbo].[City].[CityName]
AND [dbo].[Booking].[DestinationCity] = [dbo].[City].[CityName]
I guess you need a different JOIN
FROM [dbo].[Booking] as booking
LEFT OUTER JOIN [dbo].[City] as source_city
ON booking.[SourceCity] = source_city.[CityName]
LEFT OUTER JOIN [dbo].[City] as destination_city
ON booking.[DestinationCity] = destination_city.[CityName]
....
Yes it is possible, you just need to use a different table alias. Beyond referencing the same table twice, table aliases can make your code look a lot cleaner, e.g.
SELECT b.CustomerName,
sc.CityName AS SourceCity,
dc.CityName AS DestinationCity,
b.StartingDate,
b.EndingDate,
c.LicensePlateNumber,
d.DriverName,
b.AdvanceTaken,
b.PendingPayment,
b.TotalRent,
b.BookingDate,
b.IDProof
FROM dbo.Booking AS b
LEFT OUTER JOIN dbo.City AS sc
ON sc.CityName= b.SourceCity
LEFT OUTER JOIN dbo.City AS dc -- Different Alias here
ON dc.CityName = b.DestinationCity
LEFT OUTER JOIN dbo.Driver AS d
ON d.DriverID = b.DriverAllotted
LEFT OUTER JOIN dbo.Car AS c
ON c.CarID = b.CarAllotted
ORDER BY
b.BookingID;
I appreciate that cleaner is somewhat subjective, but I would be astonished if anyone found this harder to read than your original query

PostgreSQL - Why 1 search paramater works, but not the other? (multiple joined tables)

So I have a query that I run that basically looks like the one below (simplified it though for easier viewing). When I search on user_orders.orderID it works flawlessly, but if I try to search by user_orders.reference instead it just timeouts.
Now I assume that this has something to do with some of the tables that I have joined not having the reference number in them, only the orderID is present in all of them. However it would greatly simplify my work if I could search on the reference number directly, instead of the orderID.
Any advice on how to solve it?
EDIT:
Solved now, thanks everyone! It was indeed the FULL OUTER JOIN that was causing the problems, didn't fully understand what it did compared to a regular JOIN.
SELECT
user_orders.reference,
user_orders.orderid,
transfers.username,
notifications.datestamp,
orders.refund,
users.acac,
refunds.state,
decisionlog.data
FROM user_orders
FULL OUTER JOIN decisionlog ON user_orders.orderid = decisionlog.orderid
FULL OUTER JOIN refunds ON user_orders.orderid = refunds.orderid
FULL OUTER JOIN notifications ON user_orders.orderid = notifications.orderid
JOIN transfers ON user_orders.orderid = transfers.orderid
JOIN orders ON transfers.orderid = orders.orderid
JOIN users ON transfers.username = users.username
WHERE user_orders.orderid = xxx;
As suggested in the comments, if you do not have an orderid in any of decisionlog, refunds, notifications tables, this query will return a null for notifications.datestamps, refunds.state, decisionlog.data , but it will not give you an error.
Plus, take into account that using JOIN (INNER JOIN) will return you only orderid's that are on the transfer and order table and whose users are found at users table
SELECT
user_orders.reference,
user_orders.orderid,
transfers.username,
notifications.datestamp,
orders.refund,
users.acac,
refunds.state,
decisionlog.data
FROM user_orders
LEFT JOIN decisionlog ON user_orders.orderid = decisionlog.orderid
LEFT JOIN refunds ON user_orders.orderid = refunds.orderid
LFET JOIN notifications ON user_orders.orderid = notifications.orderid
INNER JOIN transfers ON user_orders.orderid = transfers.orderid
INNER JOIN orders ON transfers.orderid = orders.orderid
INNER JOIN users ON transfers.username = users.username
WHERE user_orders.reference = xxx;

Is it true that all joins following a left join in a SQL query must also be left joins? Why or why not?

I remember this rule of thumb from back in college that if you put a left join in a SQL query, then all subsequent joins in that query must also be left joins instead of inner joins, or else you'll get unexpected results. But I don't remember what those results are, so I'm wondering if maybe I'm misremembering something. Anyone able to back me up on this or refute it? Thanks! :)
For instance:
select * from customer
left join ledger on customer.id= ledger.customerid
inner join order on ledger.orderid = order.id -- this inner join might be bad mojo
Not that they have to be. They should be (or perhaps a full join at the end). It is a safer way to write queries and express logic.
Your query is:
select *
from customer c left join
ledger l
on c.id = l.customerid inner join
order o
on l.orderid = o.id
The left join says "keep all customers, even if there is no matching record in ledger. The second says, "I have to have a matching ledger record". So, the inner join converts the first to an inner join.
Because you presumably want all customers, regardless of whether there is a match in the other two tables, you would use a left join:
select *
from customer c left join
ledger l
on c.id = l.customerid left join
order o
on l.orderid = o.id
You remember correctly some parts of it!
The thing is, when you chain join tables like this
select * from customer
left join ledger on customer.id= ledger.customerid
inner join order on ledger.orderid = order.id
The JOIN is executed sequentialy, so when customer left join ledger happens, you are making sure all joined keys from customer return (because it's a left join! and you placed customers to the left).
Next,
The results of the former JOIN are joined with order (using inner join), forcing the "the first join keys" to match (1 to 1) with the keys from order so you will end up only with records that were matched in order table as well
Bad mojo? it really depends on what you are trying to accomplish.
If you want to guarantee all records from customers return, you should keep "left joining" to it.
You can, however, make this a little more intuitive to understand (not necessarily a better way of writing SQL!) by writing:
SELECT * FROM
(
(SELECT * from customer) c
LEFT JOIN
(SELECT * from ledger) l
ON
c.id= l.customerid
) c_and_l
INNER JOIN (OR PERHAPS LEFT JOIN)
(SELECT * FROM order) as o
ON c_and_l.orderid (better use c_and_l.id as you want to refer to customerid from customers table) = o.id
So now you understand that c_and_l is created first, and then joined to order (you can imagine it as 2 tables are joining again)

Postgres SQL inner join syntax

Can some one please explain the inner join syntax in the SQL below:
CREATE TABLE dataset AS
SELECT property.id
, amount.band
, amount."value"
FROM property
INNER JOIN (locality INNER JOIN amount ON locality.code = amount.code) ON (property.band = amount.band) AND (property.id = locality."UniqueId")
Why is the table locality defined before the second inner join? I've never come across such strange syntax.
Is there a more clearer way to right the same query so that someone can easily understand whats going on?
FROM property
INNER JOIN (locality INNER JOIN amount ON locality.code = amount.code)
ON (property.band = amount.band) AND (property.id = amount."UniqueId")
is the same as
FROM property
INNER JOIN amount ON property.band = amount.band AND property.id = amount."UniqueId"
INNER JOIN locality ON locality.code = amount.code
When INNER JOINs only, you can re-order them as you want.
(Any specific reason to JOIN locality? You don't select any of its columns. Is it some kind of EXISTS, or do you want multiple rows returned if there are several matching rows in that table?)

Help with SQL INNER JOIN statement

I have 2 tables , one showing me customer addresses and one other table showing all the order data. i would like to query the two tables using a JOIN so that i can get a result set shwoing me all the email addresses for customers that have not ordered in the last year.
so far i have this , but my inner join is not working, if you may help:
SELECT SHH.CUST_NO,ADR.EMAIL
FROM SALES_HISTORY_HEADER SHH,ADDRESS ADR
INNER JOIN ADR ON
SHH.CUST_NO = ADR.CUST_NO
GROUP BY SHH.CUST_NO
HAVING Max(SHH.INVOICE_DATE) < '20100728'
You were mixing join styles. If you're going to use explicit joins (and you should) then you specify the second table on the JOIN rather than listing all the tables in the FROM clause.
SELECT SHH.CUST_NO,ADR.EMAIL
FROM SALES_HISTORY_HEADER SHH
INNER JOIN ADDRESS ADR
ON SHH.CUST_NO = ADR.CUST_NO
GROUP BY SHH.CUST_NO, ADR.EMAIL
HAVING Max(SHH.INVOICE_DATE) < '20100728'