SQL Left Outer Join? - sql-server

I have table that should joint to another table based on the unique id. If I do LEFT OUTER JOIN ON I will have duplicates. If I put DISTINCT in my SELECT I will get correct number of records. Then if I include any field from the table that I did LEFT OUTER JOIN in that case I'm getting duplicates again. Here is my query:
SELECT DISTINCT
Table1.fname,
Table1.lname,
Table2.address
FROM Table1
LEFT OUTER JOIN Table2
ON Table2.user_id = Table1.userid
In the example above I'm getting duplicates, also I have tried to do:
LEFT OUTER JOIN (
SELECT user_id
FROM Table2
GROUP BY user_id
) AS t2 ON Table1.user_id = t2.user_id
This gave me correct number of records but I need some additional columns from that second table, after I include extra columns I'm getting duplicates again, example:
LEFT OUTER JOIN (
SELECT user_id, address
FROM Table2
GROUP BY user_id, address
) AS t2 ON Table1.user_id = t2.user_id
I'm wondering if I missed something or there is better way to handle this type of problem. If anyone see something or know better solution please let me know.

It is impossible for you to pick the correct answer here without understanding your data.
It seems that Table2 supports multiple addresses per user_id. This is a common design. If you want to return only one address per user_id you have several options:
Fix the data - Remove the duplicate addresses from table 2 and add a constraint that prevents this situation again. You will need to determine which addresses are incorrect.
Reduce the left join to only include one address per user - How you do this will depend on your other data. You could use min() or max() with a group by if you don't care which one to return where there are multiples or you will need to perhaps order by an effective date and take the latest one - or maybe there are billing and shipping addresses and you should pick the correct one.
Accept that there are multiple addresses per user - this may be correct - and adjust the rest of your code.

Related

How to get only last row after inner join?

I need to return unique funeral_homes who contains not completed leads and sort these by last lead timestamp.
This is my sql query:
select distinct h.funeral_home_name, h.funeral_home_guid, h.address1, h.city, h.state, p.discount_available, t.date_created
from tblFuneralHomes h inner join tblFuneralTransactions t on h.funeral_home_guid = t.funeral_home_guid
inner join vwFuneralHomePricing p on h.funeral_home_guid = p.funeral_home_guid where completed=0 order by 'funeral_home_name' asc;
This is the result, but I need only unique homes with last added lead
What I should change here?
The problem here appears that you are joining into tables with 1 to many relationships with table tblFuneralHomes, yet you expect only one row per funeral home.
Instead of using distinct, I would suggest that instead you group by the required output funeral home columns, and then apply some kind of aggregate on the columns needed from the joined tables in order to return just a single computed value from all possible joined values.
For instance, below we find the first transaction date (min) associated with each funeral home:
select h.funeral_home_name, h.funeral_home_guid, h.address1, h.city, h.state,
p.discount_available, min(t.date_created)
from tblFuneralHomes h
inner join tblFuneralTransactions t on h.funeral_home_guid = t.funeral_home_guid
inner join vwFuneralHomePricing p on h.funeral_home_guid = p.funeral_home_guid
where completed=0
group by h.funeral_home_name, h.funeral_home_guid, h.address1, h.city, h.state,
p.discount_available
order by h.funeral_home_name asc
Note that depending on the cardinality of the association between tblFuneralHomes and vwFuneralHomePricing, you may also need to remove p.discount_available from the grouping and also introduce it with an aggregate function, similar to what I've done with t.date_created

Access 2016 two table join based on a field found in another table

In advance, thank you for your assistance and explanation, I am a novice at best and trying to teach myself.
I have two different types of claims tables, [claim_a] and [claim_b]. Each of these tables capture similar data and have one claim record per row. I have a similar form to display data by record for each table. One of my forms has a grid that captures documents sent and the date sent.
In a third table, [documents], each instance of a document sent is associated with an ssn, claim_num, first, last and clm_type, doc_type and date_sent.
I want to create one query that would output all correspondence sent for both claim tables. I realize I could just do two individual queries but I think this can be done and is not too difficult, I am just missing something and would like to know what. I have tried various join type (inner, left, right) and get various results but nothing that is actually correct. With INNER JOIN, I only got 78 records but am expecting 2,261 and when I did LEFT OUTER, I got 3,070 which totals more than what I had in my [documents] table-I do understand that an outer join with one row in the LEFT table that matches two rows in the RIGHT table will return as two ROWS.
I have also been sure to use parenthesis in my first join statement which based on Google searches seems to be related to Access. I also tried using where clauses too.
I think the problem may be that some of the records in [documents] do not correspond to a record in either claims table. I also just tried joining one claim table to [documents] but even that did not return the expected number of results.
Here are few of the joins I have tried:
Inner Join for one table: My output was missing 4 records for an SSN with 6 total records and I could not figure out why it skipped over the remaining 4. It was only for this SSN. I had other SSNs with more than 6 records.
SELECT documents.date, documents.doc_type,
FROM documents INNER JOIN claim_a ON documents.ssn =
claim_a.ssn WHERE (((documents.clm_type)="Life Only")) OR
(((documents.clm_type)<>("Health")) AND (("Life/ ADB")<>False) AND
(("Life")<>False));
I got 78 records with this join
SELECT documents.date, documents.doc_type,
FROM (documents INNER JOIN claim_a ON documents.ssn =
claim_a.ssn) INNER JOIN claim_b ON documents.ssn =
claim_b.ssn;
I got 3070 records with this join
SELECT documents.date, documents.doc_type,
FROM (documents LEFT OUTER JOIN claim_a ON documents.ssn =
claim_a.ssn) LEFT OUTER JOIN claim_b ON documents.ssn =
claim_b.ssn;
I got the correct number of results with this query but I am concerned it will not work with my Master Form to display header specific information for my form associated with table, claim_b.
SELECT documents.date, documents.doc_type,
FROM documents LEFT JOIN claim_a ON documents.ssn =
claim_a.ssn WHERE (((documents.clm_type)<>""));
I am obviously doing something wrong. Can someone please advise?
Sounds like you need a Union query between the two claims tables to get a list of all claims. Then use the results of theat query to get the document list.
Union query
Select ssn from claim_a
Union all select ssn from claim_b
Save this with a name like SSN_List, then join it to Documents in another query
Select * from Documents
left join SSN_List on Documents.ssn=SSN_List.ssn
And of course change the 2nd query as needed to get the information you need from Documents.
This can probably be done in one query, but I find it easier to understand and use the 2 step approach.

Find matching records of two different tables in SQL Server

I have two tables in one of them a seller saves a record for a product he is selling. and in another table buyers save what they need to buy.
I need to get a list of user ids (uid field) from buyers table which matches a specific product on sales table. this is what I have written:
select n.[uid]
from needs n
left join ads(getdate()) a
on n.mid=a.mid
and a.[year] between n.from_year and n.to_year
and a.price between n.from_price and n.to_price
and n.[uid]=a.[uid]
and a.pid=n.pid
Well I need to use a where clause to eliminate those records which doesn't match. as I think all of these conditions are defined with ON must be defined with a where clause. but joining needs at least one ON clause. may be I shouldn't join two tables? what can I do?
There is an important difference between LEFT JOIN and JOIN, or more accurately OUTER and INNER joins respectively.
Inner joins require that both sides of the join match. In other words, if you:
had a table representing People
you had another table representing Automobiles
and each automobile had a PersonId
and joined these tables using ON with the PersonId
using LEFT (OUTER) JOIN would return all people, even those without automobiles. INNER JOIN only returns the people with vehicles.
This article may help: http://www.codinghorror.com/blog/2007/10/a-visual-explanation-of-sql-joins.html

SQL Same Column in one row

I have a lookup table that has a Name and an ID in it. Example:
ID NAME
-----------------------------------------------------------
5499EFC9-925C-4856-A8DC-ACDBB9D0035E CANCELLED
D1E31B18-1A98-4E1A-90DA-E6A3684AD5B0 31PR
The first record indicates and order status. The next indicates a service type.
In a query from an orders table I do the following:
INNER JOIN order.id = lut.Statusid
This returns the 'cancelled' name from my lookup table. I also need the service type in the same row. This is connected in the order table by the orders.serviceid How would I go about doing this?
It Cancelled doesnt connect to 31PR.
Orders connects to both. Orders has 2 fields in it called Servicetypeid and orderstatusid. That is how those 2 connect to the order. I need to return both names in the same order row.
I think many will tell you that having two different pieces of data in the same column violates first normal form. There is a reason why having one lookup table to rule them all is a bad idea. However, you can do something like the following:
Select ..
From order
Join lut
On lut.Id = order.StatusId
Left Join lut As l2
On l2.id = order.ServiceTypeId
If order.ServiceTypeId (or whatever the column is named) is not nullable, then you can use a Join (inner join) instead.
A lot of info left out, but here it goes:
SELECT orders.id, lut1.Name AS OrderStatus, lut2.Name AS ServiceType
FROM orders
INNER JOIN lut lut1 ON order.id = lut.Statusid
INNER JOIN lut lut2 ON order.serviceid = lut.Statusid

Iterating 1 row at a time with massive amounts of links/joins

Ok, basically what is needed is a way to have row numbers while using a lot of joins and having where clauses using these rownumbers.
such as something like
select ADDRESS.ADDRESS FROM ADDRESS
INNER JOIN WORKHISTORY ON WORKHISTORY.ADDRESSRID=ADDRESS.ADDRESSRID
INNER JOIN PERSON ON PERSON.PERSONRID=WORKHISTORY.PERSONRID
WHERE PERSONRID=<some number> AND WORKHISTORY.ROWNUMBER=1
ROWNUMBER needs to be generated for this query on that one table though. So that if we want to access the second WORKHISTORY record's address, we could just go WORKHISTORY.ROWNUMBER=2 and if say we had two address's that matched, we could cycle through the addresses for one WORKHISTORY record using ADDRESS.ROWNUMBER=1 and ADDRESS.ROWNUMBER=2
This should be capable of being an automatically generated query. Thus, there could be more than 10 inner joins in order to get to the relevant table, and we need to be able to cycle through each table's record independently of the rest of the tables..
I'm aware there is the RANK and ROWNUMBER functions, but I'm not seeing how it will work for me because of all the inner joins
note: in this example query, ROWNUMBER should be automatically generated! It should never be stored in the actual table
Can you use a temp table?
I ask because you can write the code like this:
select a.field1, b.field2, c.field3, identity (int, 1,1) as TableRownumber into #temp
from table1 a
join table2 b on a.table1id = b.table1id
join table3 c on b.table2id = c.table2id
select * from #temp where ...

Resources