Joining two tables - multiple columns to single column - sql

Table 1
-------
LANG_VALUE
LANG_DESC
Table 2
-------
EmpId
LANG1
LANG2
LANG3
LANG4
LANG5
LANG6
It looks like as below:
Table 1
-------
LANGVALUE LANGDESC
-------------------
SPAN SPANISH
GERM GERMAN
Table 2
-------
EmpId LANG1 LANG2 LANG3 LANG4 LANG5 LANG6
-----------------------------------------
1 SPAN NULL NULL NULL NULL NULL
2 GERM SPAN NULL NULL NULL NULL
3 GERM NULL NULL NULL NULL NULL
Expected Result:
EmpId LANG1 LANG2 LANG3 LANG4 LANG5 LANG6
-----------------------------------------
1 SPANISH NULL ...
2 GERMAN SPANISH NULL...
3 GERMAN NULL...
How to do this in sql query?

SELECT EmpId,
K1.LANGDESC AS LANG1,
K2.LANGDESC AS LANG2,
K3.LANGDESC AS LANG3,
K4.LANGDESC AS LANG4,
K5.LANGDESC AS LANG5,
K6.LANGDESC AS LANG6
FROM Table2 T
LEFT JOIN Table1 K1 ON K1.LANGVALUE = T.LANG1
LEFT JOIN Table2 K2 ON K2.LANGVALUE = T.LANG2
LEFT JOIN Table3 K3 ON K3.LANGVALUE = T.LANG3
LEFT JOIN Table4 K4 ON K4.LANGVALUE = T.LANG4
LEFT JOIN Table5 K5 ON K5.LANGVALUE = T.LANG5
LEFT JOIN Table6 K6 ON K6.LANGVALUE = T.LANG6
WHERE...
Note: this unsolicited in the question, but it may be a good idea to consider a schema where the Employee to Language is stored in a separate table, in a one-to-many fashion. This will allow having employees with more than 6 languages (hope you have many of these...) as well as not carrying so many nulls for employees that ain't so polyglot, and more importantly it would allow querying say all employees with a particular language without having to worry if that is to be found in the LANG2, or LANG3 etc...
Note, the Employee-Langage table could also have an attribute indicating the "order" (or the level of fluency), so that you can also search for employees who's first listed language is x.

I think you'd have to do this with subqueries based on the format of your table 2. I have the distinct feeling you aren't properly normalized for table-2, which is why you have this problem in the first place.
select EmpId,(Select LANGDESC from [Table 1] t1 where t2.Lang1=LANGVALUE) as LANG1,(and so on) where from [Table 2] t2

Related

How to join three tables and set blank fields to null?

I used full join and left join to join the Person, Tasks and Task tables. The result shown on the screen resulted in a number of lines greater than six. Unset fields have the value NULL and that's good.
The expected output can be obtained using such joins, however it is necessary to use clauses that allow the common fields to be joined. How can I do this?
A CROSS JOIN produces all the combinations you want. Then a simple outer join can retrieve the related rows (should they exist).
You don't mention the database you are using so a faily standard query will do. For example (in PostgreSQL):
select
row_number() over(order by p.id, t.id) as id,
p.name,
case when x.st is not null then t.hr end,
x.st
from person p
cross join tasks t
left join task x on x.personid_fk = p.id and x.taskid_fk = t.id
order by p.id, t.id;
Result:
id name case st
--- ----- ------ -----
1 Anna null null
2 Anna null null
3 Luo 13:00 true
4 Luo 14:00 false
5 John null null
6 John null null
See running example at DB Fiddle.

JOIN query, SQL Server is dropping some rows of my first table

I have two tables customer_details and address_details. I want to display customer details with their corresponding address, so I was using a LEFT JOIN, but when I'm executing this query, SQL Server drops rows where street_no of customer_details table doesn't match with the street_no in address_detials table and displays only rows where `street_no' of customer_detials = street_no of address_details table. I need to display a complete customer_details table and in case if street_no doesn't matches it should display empty string or anything. Am I doing anything wrong in my SQL join?
Table customer_details:
case_id customer_name mob_no street_no
-------------------------------------------------
1 John 242342343 4324234234234
1 Rohan 343233333 43332
1 Ankit 234234233 2342332423433
1 Suresh 234234324 2342342342342
1 Ranjeet 343424323 32233
1 Ramu 234234333 2342342342343
Table address_details:
s_no streen_no address city case_id
------------------------------------------------------
1 4324234234234 Roni road Delhi 1
2 2342332423433 Natan street Lucknow 1
3 2342342342342 Koliko road Herdoi 1
SQL JOIN query:
select
a.*, b.address
from
customer_details a
left join
address_details b on a.street_no = b.street_no
where
b.case_id = 1
Now that it became clear that you used b.case_id=1, I will explain why it filters:
The LEFT JOIN itself returns some rows that contain all NULL values for table b in the result set, which is what you want and expect.
But by using WHERE b.case_id=1, the rows containing NULL values for table b are filtered out because none of them matches the condition (all those rows have b.case_id=NULL so they don't match).
It might work to instead use WHERE a.case_id=1, but we don't know if a.case_id and b.case_id are always the same value for matching rows (they might not be; and if they are always the same, then we just identified a potential redundancy).
There are two ways to fix this for sure.
(1) Move b.case_id = 1 into the left join condition:
left join address_details b on a.street_no = b.street_no and b.case_id = 1
(2) Keep b.case_id = 1 in the WHERE but also allow for NULLED-out b values:
left join address_details b on a.street_no = b.street_no
where b.case_id = 1
or b.street_no IS NULL
Personally I'd go for (1) because that is the most clear way to express that you want to filter b on two conditions, without affecting the rows of a that are being returned.
I do think that Wilhelm Poggenpohl answer is kind of right. You just need to change the last join condition a.case_id=1 to b.case_id=1
select a.* , b.address
from customer_details a
left join address_details b on a.street_no=b.street_no
and b.case_id=1
This query will show every row from customer_details and the corresponding adress if there is a match of street_no and the adress meets the condition case_id=1.
This is because of the where clause. Try this:
select a.* , b.address
from customer_details a
left join address_details b on a.street_no=b.street_no
and a.case_id=1

How to compare two different tables based on two different Columns in SQL Server?

The first table consists of Accounts with State and Country information which are mostly correct with few wrong rows:
ID NAME State Country
--------------------------------------------------
1 Account 1 NJ USA
2 Account 2 NY NULL
3 Account 3 Beijing Japan
And I have the second table which has the correct state and County information to which the first tables needs to be compared to:
State_Code State Country_Code Country
-------------------------------------------------------
01 NJ A01 USA
02 NY A01 USA
03 Beijing c01 China
The query should check if the state in the first table exists in the second table and if it does, is it associated with the correct country and the result would be a table of rows with wrong info:
So in my example, the comparison should give me the result:
ID NAME State Country
------------------------------------------------------
2 Account 2 NY NULL
3 Account 3 Beijing Japan
I am a beginner trying to learn more about SQL and I tried solving this using left join and outer join both of which didn't give me the correct result. I would be very grateful if some one could point me in the right direction or give me an example on how I should approach this.
(I am using Microsoft SQL Server Management Studio)
Please try this. You can change the join condition if you need any changes.
Data
CREATE TABLE firstTable
(
ID INT
,NAME VARCHAR(10)
,State VARCHAR(10)
,Country VARCHAR(10)
)
GO
INSERT INTO firstTable VALUES
(1 ,'Account 1','NJ','USA'),
(2 ,'Account 2','NY',NULL),
(3 ,'Account 3','Beijing','Japan')
GO
CREATE TABLE SecondTable
(
State_Code VARCHAR(10)
,State VARCHAR(10)
,Country_Code VARCHAR(10)
,Country VARCHAR(10)
)
GO
INSERT INTO SecondTable VALUES
('01','NJ' ,'A01','USA'),
('02','NY' ,'A01','USA'),
('03','Beijing' ,'c01','China')
GO
SOLUTION
select f.* from firstTable f
FULL JOIN SecondTable s
ON f.State = s.State and f.Country = s.Country
WHERE f.State IS NOT NULL AND ( s.Country_Code IS NULL OR s.State IS NULL )
OUTPUT
ID NAME State Country
----------- ---------- ---------- ----------
2 Account 2 NY NULL
3 Account 3 Beijing Japan
(2 rows affected)
You want to join the two tables on the State and look for records where the Country doesn't match. This query should get you there:
SELECT t1.*, t2. Country AS Expected
FROM table1 t1
JOIN table2 t2 ON t1.State = t2.State
WHERE t1.County != t2.Country
Unfortunately, I don't know your table names, so I just had to go with table1 and table2, but hopefully this gives you what you need. I also added in the expected Country, but you can remove that if you don't need it.
I think what you're looking for is "NOT EXISTS". Basically you look for any state/country combos in the first table that don't exist in the second table. Here's an example.
SELECT tbo.ID, tbo.NAME, tbo.STATE, tbo.COUNTRY
FROM TableOne tbo
WHERE NOT EXISTS(
SELECT * FROM TableTwo tbt
WHERE tbo.State = tbt.State
AND tbo.Country = tbt.Country
)

pad database out with NULL criteria

If I have the following sample table (order by ID)
ID Date Type
-- ---- ----
1 01/01/2000 A
2 22/04/1995 A
2 14/02/2001 B
Where you can immediate see that ID=1 does not have a Type=B, but ID=2 does. What I want to do, if fill in a line to show this:
ID Date Type
-- ---- ----
1 01/01/2000 A
1 NULL B
2 22/04/1995 A
2 14/02/2001 B
where there could potentially be 100's of different types, (so may need to end up inserting 100's rows per person if they lack 100's Types!)
Is there a general solution to do this?
Could I possibly outer join the table on itself and do it that way?
You can do this with a cross join to generate all the rows and a left join to get the actual data values:
select i.id, s.date, t.type
from (select distinct id from sample) i cross join
(select distinct type from sample) t left join
sample s
on s.id = i.id and
s.type = t.type;

How to have multiple tables with multiple joins

I have three tables that I need to join together and get a combination of results. I have tried using left/right joins but they don't give the desired results.
For example:
Table 1 - STAFF
id name
1 John
2 Fred
Table 2 - STAFFMOBILERIGHTS
id staffid mobilerightsid rights
--this table is empty--
Table 3 - MOBILERIGHTS
id rightname
1 Login
2 View
and what I need is this as the result...
id name id staffid mobilerightsid rights id rightname
1 John null null null null 1 login
1 John null null null null 2 View
2 Fred null null null null 1 login
2 Fred null null null null 2 View
I have tried the following :
SELECT *
FROM STAFFMOBILERIGHTS SMR
RIGHT JOIN STAFF STA
ON STA.STAFFID = SMR.STAFFID
RIGHT JOIN MOBILERIGHTS MRI
ON MRI.ID = SMR.MOBILERIGHTSID
But this only returns two rows as follows:
id name id staffid mobilerightsid rights id rightname
null null null null null null 1 login
null null null null null null 2 View
Can what I am trying to achieve be done and if so how?
Thanks
From your comment its now clear you want a cross join (include all rows from staff and mobilerights). Something like this should do it
SELECT
*
FROM Staff, MobileRights
LEFT OUTER JOIN StaffMobileRights ON StaffMobileRights.StaffId = Staff.Id
The FROM clause specifies that we will be including all rows from the Staff table, and all rows from the MobileRights table. The end result will therefore contain (staff * MobileRights) rows.
To bring in rows from StaffMobileRights then we need a join to that table also. We use a LEFT OUTER join to ensure that we always include the left side (rows in the staff table) but we arent too bothered if no rows exist on the right side (StaffMobileRights table). If no row exists for the join then null values are returned.
What you are probably asking is to see null where is no rights. In the rectangular style that results are always returned, this is the only way to represent it with a simple join:
From PaulG's query i changed it a bit to always get everything form the STAFF table.
SELECT
*
FROM STAFF
RIGHT OUTER JOIN StaffMobileRights ON StaffMobileRights.StaffId = Staff.Id
INNER JOIN MobileRights ON MobileRights.Id = StaffMobileRights.MobileRightsId