Add two string columns from different tables - sql

I am trying to add two columns together of char data type in order to combine their code with description.
table1 has all of the data I need and I am only referencing table2 in order to get the description.
For example, table1 has column:
Code
1
2
and table 2 has columns:
Code Description
1 Football
2 Soccer
I'm basically trying to write a query where I can have one column show
1 - Football
2 - Soccer
I have tried:
SELECT
a.Code + ' - ' + b.Description
FROM table1 a
LEFT JOIN table2 b
ON a.Code = b.Code
and while this does add the columns together, it also generates a lot of duplicate rows for some reason, I am assuming because of the LEFT JOIN.
Basically I am just wanting that whatever code is in table1, to match that code in table2 and to bring over that Description.

With the Left Join you get the values in Table A that may not exist in Table B. To eliminate the duplicates you could try
SELECT DISTINCT
a.Code + ' - ' + b.Description
FROM table1 a
LEFT JOIN table2 b
ON a.Code = b.Code
OR
SELECT
a.Code + ' - ' + b.Description
FROM table1 a
LEFT JOIN table2 b
ON a.Code = b.Code
GROUP BY a.Code, b.Description

You could use ISNULL to handle missing value from table2:
SELECT
a.Code + ISNULL(' - ' + b.Description, '')
FROM table1 a
LEFT JOIN table2 b
ON a.Code = b.Code

use coalesce in case of null for 2nd table and use distinct incase of avoid duplicate
SELECT distinct a.Code +' - ' + coalesce(b.Description,'')
FROM table1 a
LEFT JOIN table2 b
ON a.Code = b.Code
or try like below and i dont think you needed join you can do it just by using 2nd tabale
SELECT
b.Code ||' - ' || b.Description)
from
table2 b

What is the relationship between table1 and table2? The only way I see the above query returning duplicates is: If relationship between table1 and table2 is 1:Many. Meaning one row in table1 can match to multiple rows in table2.
Do you need to fetch a code that exists in table1 even if it does not have a corresponding description in table2? If so, use a LEFT JOIN like below.
If table2 has direct duplicates, then using a DISTINCT will remove
duplicates in the final result:
SELECT DISTINCT
a.Code + ' - ' + COALESCE(b.Description, '')
FROM table1 a
LEFT JOIN table2 b
ON a.Code = b.Code;
If one code has multiple different descriptions in table2, then your
final resultset is expected to have multiple rows for the same code
but with different description by running the above query because of
the nature of data in the tables.
Do you need to fetch a code that exists in table1 only if it has a corresponding description in table2? If so, use a INNER JOIN like below.
SELECT DISTINCT
a.Code + ' - ' + b.Description
FROM table1 a
INNER JOIN table2 b
ON a.Code = b.Code;

Related

SQL Server Update sub query with formula not quite right

I have a table (table1) of names and their frequencies
Name-----Frequency
Mike-------0.56
Fred-------0.30
Nancy------0.14
and a Cartesian product (table2) where the names are paired in two columns and a third column where I would like to sum the frequencies from table1 by matching the names in the first two columns back to table1.
Name1-------Name2------sum
Mike--------Fred
Mike--------Nancy
Fred--------Nancy
I want to update the sum column of table2 using the frequencies in table 1 with a subquery in the update for the matching names (Or so this is how I imagine I need to do it). If there is a better way please let me know.
I have:
UPDATE table2
SET sum = (SELECT dbo.table1.Frequency WHERE Name1 = dbo.table1.Name) +
(SELECT dbo.table1.Frequency WHERE Name2 = dbo.table1.Name)
FROM table1
I get a table full of NULLs instead of the frequency sums.
Am I going about this the right way? Am I totally missing how to do this and there is a better way to do it?
Try updating from a join like this:
update a
set a.sum=isnull(b.frequency,0)+isnull(c.frequency,0)
from table2 a
left join table1 b on a.name1=b.name
left join table1 c on a.name2=c.name
Your method is fine. If all names match:
UPDATE t2
SET sum = (SELECT f.frequency FROM dbo.table1.Frequency f WHERE t2.Name1 = f.Name) +
(SELECT f.frequency FROM dbo.table1.Frequency f WHERE t2.Name2 = f.Name)
FROM table2 t2;
If they don't, then use isnull() (or coalesce(), but isnull() is more efficient):
UPDATE t2
SET sum = isnull( (SELECT f.frequency FROM dbo.table1.Frequency f WHERE t2.Name1 = f.Name), 0) +
isnull( (SELECT f.frequency FROM dbo.table1.Frequency f WHERE t2.Name2 = f.Name), 0)
FROM table2 t2;

Inner join on ConCat fields

I have table A
Code Range
A 12569
B 18175
C 478931
And Table B
id Type
A12569 0
B18175 1
C478931 0
How can I concatenate the two fields of the first table, in order to join them with the second table.
I have tried with the following query
SELECT concat(A.code,B.Range),b.Type FROM DB.tableA A
inner join DB.tableB B
on Concat(A.code,B.Range)= B.id;
Just concatenate the two columns:
select *
from table_a a
join table_b b on a.code||range = b.id;
The above is standard SQL - not all DBMS respect that though and use a different operator to concatenate strings.
SQL Server:
Select a.Code+b.Range as id, b.Type from TableA a inner join tableB b on a.Code + b.Range = b.id
Untested but should work - presumption is all columns are varchar or nvarchar. May need to add some casting on the range field if that's not the case.

Joining two tables where id does not equal

I'm struggling getting this query to produce the results I want.
I have:
table1, columns=empid, alt_id
table2, columns=empid, alt_id
I want to get the empid, and alt_id from table 1 where the alt_id does not match the alt_id in table2. They will both have alt_id numbers I just want to get the ones that do not match.
Any ideas?
SELECT * FROM table1
INNER JOIN table2 ON table2.empid = table1.empid AND table2.alt_id <> table1.alt_id
What does that really mean though? Normally when this is asked, it is of the form "I want all rows from A that have no row matching in B and all in B that have no match in A"
Which looks like this:
SELECT * FROM
A
FULL OUTER JOIN
B
ON
a.id = b.id
You'll see a null for any row data where there isn't a matching row on the other side:
A.id
1
2
B.id
1
3
Result of full outer join:
A.id B.id
1 1
2 null
null 3
You, however have asked for A-B join where the IDs aren't equal, which would be the more useless query of:
SELECT * FROM
A
INNER JOIN
B
ON
a.id != b.id
And it would look like:
A.id B.id
1 3
2 1
2 3
You seem to want not exists:
select t1.*
from table1 t1
where not exists (select 1 from table2 t2 where t2.alt_id = t1.alt_id);
It is unclear whether or not you also want to join on empid, so you might really want:
select t1.*
from table1 t1
where not exists (select 1 from table2 t2 where t2.alt_id = t1.alt_id and t2.empid = t1.empid);
A left join will find all records in Table A that do not match those in Table B. Then use a Where filter to find the Nulls from Table B. That will give you all those in Table A that do not have a matching ID in Table B.
Select A.*
from Table A
Left Join
Table B
on a.altid = b.altid
where b.altid is null;
select *
from [Login] L inner join Employee E
on l.EmployeeID = e.EmployeeID
where l.EmployeeID not in (select EmployeeID from Employee)

How to use SQL Joins and Selects to get results from a third table that matches the first two?

I have a Join statement on two tables(Table 1 and 2), which returns the City and State. I have another table(Table 3) which contains columns like Name, City, State, Country. I want to fetch all the rows from Table 3 whose City and State Columns matches with the rows of the Join result.
Select * from 3rdTable where City='' AND State='';
Result from Join is like
- City | State
- A | B
- C | D
- E | F
Example Result if only 1 row of the 3rd table matches
- C | D
How can this be done?
You can use the joined table as a sub table in 3rdTable to create a where clause as follows;
select *
from 3rdTable
where City+'|'+State= (select a.City+'|'+b.State
from a
inner join b
on a.x=b.y)
Buy concatenating the fields, you can create a single equality to the joined subquery
Be sure about the joins, we have inner join, Left join, right join and outer join; maybe knowing the difference can help you to answer your question.
and also the code is not clear :)
Just join in the 3rd table...
IF we assume table1 has both city and state in it...
SELECT A.City, A.State
FROM Table1 A
INNER JOIN table2 B
on A.PK = B.A_FK
INNER JOIN table3 C
on A.City = C.City
and A.State = C.State
This is the nature of an inner join: Include all rows from all tables where the joined data matches.
If you use an OUTER join (left, right, full outer) then you get all records from one table and only those that match in the others, or full outer all records from all tables aligned where they match.
SELECT *
FROM table3 t3
INNER JOIN (SELECT city,
state
FROM table1 T1
JOIN table2 t2
ON t1.id = t2.id) a1
ON t3.city = a1.city
AND t3.state = a1.state
I think this could help you:
SELECT T3.*
FROM
table_1_2_join T12 /* replace this placeholder table with the select statement that joins your 2 tables */
JOIN table_3 T3 ON T3.City = T12.city AND T3.state = T12.state
Let me know if you need more details.

An issue possibly related to Cursor/Join

Here is my situation:
Table one contains a set of data that uses an id for an unique identifier. This table has a one to many relationship with about 6 other tables such that.
Given Table 1 with Id of 001:
Table 2 might have 3 rows with foreign key: 001
Table 3 might have 12 rows with foreign key: 001
Table 4 might have 0 rows with foreign key: 001
Table 5 might have 28 rows with foreign key: 001
I need to write a report that lists all of the rows from Table 1 for a specified time frame followed by all of the data contained in the handful of tables that reference it.
My current approach in pseudo code would look like this:
select * from table 1
foreach(result) {
print result;
select * from table 2 where id = result.id;
foreach(result2) {
print result2;
}
select * from table 3 where id = result.id
foreach(result3) {
print result3;
}
//continued for each table
}
This means that the single report can run in the neighbor hood of 1000 queries. I know this is excessive however my sql-fu is a little weak and I could use some help.
LEFT OUTER JOIN Tables2-N on Table1
SELECT Table1.*, Table2.*, Table3.*, Table4.*, Table5.*
FROM Table1
LEFT OUTER JOIN Table2 ON Table1.ID = Table2.ID
LEFT OUTER JOIN Table3 ON Table1.ID = Table3.ID
LEFT OUTER JOIN Table4 ON Table1.ID = Table4.ID
LEFT OUTER JOIN Table5 ON Table1.ID = Table5.ID
WHERE (CRITERIA)
Join doesn't do it for me. I hate having to de-tangle the data on the client side. All those nulls from left-joining.
Here's a set-based solution that doesn't use Joins.
INSERT INTO #LocalCollection (theKey)
SELECT id
FROM Table1
WHERE ...
SELECT * FROM Table1 WHERE id in (SELECT theKey FROM #LocalCollection)
SELECT * FROM Table2 WHERE id in (SELECT theKey FROM #LocalCollection)
SELECT * FROM Table3 WHERE id in (SELECT theKey FROM #LocalCollection)
SELECT * FROM Table4 WHERE id in (SELECT theKey FROM #LocalCollection)
SELECT * FROM Table5 WHERE id in (SELECT theKey FROM #LocalCollection)
Ah! Procedural! My SQL would look like this, if you needed to order the results from the other tables after the results from the first table.
Insert Into #rows Select id from Table1 where date between '12/30' and '12/31'
Select * from Table1 t join #rows r on t.id = r.id
Select * from Table2 t join #rows r on t.id = r.id
--etc
If you wanted to group the results by the initial ID, use a Left Outer Join, as mentioned previously.
You may be best off to use a reporting tool like Crystal or Jasper, or even XSL-FO if you are feeling bold. They have things built in to handle specifically this. This is not something the would work well in raw SQL.
If the format of all of the rows (the headers as well as all of the details) is the same, it would also be pretty easy to do it as a stored procedure.
What I would do: Do it as a join, so you will have the header data on every row, then use a reporting tool to do the grouping.
SELECT * FROM table1 t1
INNER JOIN table2 t2 ON t1.id = t2.resultid -- this could be a left join if the table is not guaranteed to have entries for t1.id
INNER JOIN table2 t3 ON t1.id = t3.resultid -- etc
OR if the data is all in the same format you could do.
SELECT cola,colb FROM table1 WHERE id = #id
UNION ALL
SELECT cola,colb FROM table2 WHERE resultid = #id
UNION ALL
SELECT cola,colb FROM table3 WHERE resultid = #id
It really depends on the format you require the data in for output to the report.
If you can give a sample of how you would like the output I could probably help more.
Join all of the tables together.
select * from table_1 left join table_2 using(id) left join table_3 using(id);
Then, you'll want to roll up the columns in code to format your report as you see fit.
What I would do is open up cursors on the following queries:
SELECT * from table1 order by id
SELECT * from table1 r, table2 t where t.table1_id = r.id order by r.id
SELECT * from table1 r, table3 t where t.table1_id = r.id order by r.id
And then I would walk those cursors in parallel, printing your results. You can do this because all appear in the same order. (Note that I would suggest that while the primary ID for table1 might be named id, it won't have that name in the other tables.)
Do all the tables have the same format? If not, then if you have to have a report that can display the n different types of rows. If you are only interested in the same columns then it is easier.
Most databases have some form of dynamic SQL. In that case you can do the following:
create temporary table from
select * from table1 where rows within time frame
x integer
sql varchar(something)
x = 1
while x <= numresults {
sql = 'SELECT * from table' + CAST(X as varchar) + ' where id in (select id from temporary table'
execute sql
x = x + 1
}
But I mean basically here you are running one query on your main table to get the rows that you need, then running one query for each sub table to get rows that match your main table.
If the report requires the same 2 or 3 columns for each table you could change the select * from tablex to be an insert into and get a single result set at the end...