SQL Same Column in one row - sql-server

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

Related

How to join two tables in SQL Server, where the IDs are not the same?

I have 2 tables in MS SQL and I am using MS Studio. The first table is called register it has a list of fields. The second table is called Plan and it has a list of fields.
The unique key in the table register is called RegisterID
The unique key in the table Plan is called RegisterID
The goal is to link with a left join the Register to the Plan. My difficulty is that the IDs are not exactly the same: An ID in Plan is xxxx (xxxx being the value of the ID). An ID in Register is xxxx_0 (xxxx being the same value than Plan was added _0)
What is the solution to link those 2 tables in a simple query with fields of both tables?
Here is some more information.
You will find the 2 tables and the expect result of the query.
Tables structure
Expected result
Please note that I am a beginner.
Add the characters to the first field or remove them from the second
select *
from register
left outer join plan on register.RegisterID+'_0' = plan.RegisterID
select *
from register
left outer join plan on register.RegisterID = REPLACE(plan.RegisterID,'_0','')
If the length of the ID is always the same there is a third option
select *
from register
left outer join plan on register.RegisterID = LEFT(plan.RegisterID,6)
You could try something like:
SELECT *
FROM Register R
LEFT OUTER JOIN [Plan] P
ON LEFT(R.RegisterID, LEN(R.RegisterID) - 2) = P.RegisterID
The expression LEFT(R.RegisterID, LEN(R.RegisterID) - 2) will remove the '_0' from Register.RegisterID and the JOIN will work.

Microsoft SQL -- struggles with CROSS JOIN

So i have to do a cartesian product (or CROSS JOIN) between two tables. One problem is that both tables have a column with the name 'itemname'. My current case looks as follows:
select *
into #cartesian_temp
from xsale CROSS JOIN xitem
delete from #cartesian_temp where deptname='books' and itemcolor='bamboo'
select * from #cartesian_temp
so the error I get is:
Column names in each table must be unique. Column name 'itemname' in table '#cartesian_temp' is specified more than once
Anyone that can help me with my problem?
you can add alias for the columns like below.
select XS.itemname as saleitemname , XI.itemname as saleitemname2
into #cartesian_temp
from xsale XS CROSS JOIN xitem XI
This is one of the reasons why seasoned SQL pro's will ALWAYS advocate to give Tables an alias and to ALWAYS fully qualify every column name by using the alias. It's not just a cross join problem
Avoid this:
SELECT *
FROM
person
INNER JOIN
address
ON addressid = address.id -- Person.addressid
Sure, it'll work as long as the column names are all unique (it'll probably cause issues even now because person will have an I'd column and so will address) but it might stop working at any point in future if someone adds columns to either table with names that clash
Prefer this:
SELECT p.id as personid, a.id as addressid, p.name, a.zipcode
FROM
person p
INNER JOIN
address a
ON p.addressid = a.id
This is fully aliased (both tables have an alias) and we haven't used select *; weve fully qualified every column with a prefix using the table alias and we've aliased columns that have the same named (the ID columns) in each table so we can tel them apart. No one can add any columns to the db and cause this query to stop working
Aliasing Tables helps in another way; it lets us use the same table twice in a query. Suppose a person had a work address and a home address:
SELECT ...
FROM
person p
INNER JOIN
address awork
ON p.workaddressid = awork.id
INNER JOIN
address ahome
ON p.homeaddressid = ahome.id
This is impossible without aliasing. Always give aliases a sensible name (not a1, a2)
For your case, go like:
SELECT xs.itemname as xsitemname, xi.itemname as xiitemname, ...
FROM
xsale xs
CROSS JOIN
xitem xi
WHERE
xi.itemcolor = 'green'
This will be every green item crossed with every sale item

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

SQL Left Outer Join?

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.

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