can we get the data from five tables having a common id with one query? - sql

i want to get the data of five table having a common id from one query can we do this ,
for example tbl_student,tbl_batch,tbl_section,tbl_level,tbl_faculty all have a common id
college_id
how can i get all the tables value with one query
if anybody can help me i would be greatful

If I understand you correctly that sounds like a join.
select * from tbl_student st
join tbl_batch ba on ba.college_id=st.college_id
join tbl_section se on se.college_id=st.college_id
join tbl_level le on le.college_id=st.college_id
join tbl_faculty fa on fa.college_id=st.college_id
This is most probably not exactly the way you want to get the data because the data model would not make much sense. Hopefully you get the idea though.

SELECT fields FROM table1
LEFT JOIN table2 ON table1.id = table2.id
LEFT JOIN table3 ON table1.id = table3.id
LEFT JOIN table4 ON table1.id = table4.id

You can do it, but it won't make a lot of sense.
Your SQL query returns a 2-D table with the same columns for each row. If some of your rows are students and some of them are faculties, then there will be a bunch of columns that make sense for students but don't make sense for faculties, and for a faculty row those columns should be null.
The SQL to do this for two tables is:
SELECT t_F.college_id AS college_id, t_F.f_1, t_F.f_2, NULL , NULL
FROM tbl_Faculty AS t_F
UNION
SELECT t_S.college_id AS college_id, NULL , NULL , t_S.s_1, t_S.s_2
FROM tbl_Student AS t_S
ORDER BY college_id
Then your results will look like:
college| Faculty field 1 | 2 | Student field 1 | 2
--------------------------------------------------------------
1 | abc | def | NULL | NULL
1 | abc | ghi | NULL | NULL
1 | NULL | NULL| asdoifjas | aosdifjasdf
1 | NULL | NULL| asdoifjas | aosdifjasdf
2 | abc321 | aaa | NULL | NULL
2 | abc456 | bbb | NULL | NULL
2 | NULL | NULL| afasdfafs | aosdifjasdf
2 | NULL | NULL| asdoifjas | aoffavsdfff
This doesn't make that much sense to me.

Related

How to join multiple columns in one table to another lookup table?

I am unable to figure out how to join a couple of tables together when multiple columns in one table refer to another table.
For example, I have a "document_statuses" table:
document_statuses table:
+-----------+-------------+
| status_id | status_name |
+-----------+-------------+
| 1 | RECEIVED |
| 2 | MISSING |
| 3 | NOT_NEEDED |
+-----------+-------------+
Now in another table, I am tracking the status of multiple documents:
filings table:
+-----------+-------------+----------------+----------------+----------------+
| filing_id | filing_name | doc1_status_id | doc2_status_id | doc3_status_id |
+-----------+-------------+----------------+----------------+----------------+
| 1 | John | 1 | 3 | 2 |
| 2 | Mikaela | 2 | 3 | 2 |
| 3 | Sam | 1 | 2 | 1 |
+-----------+-------------+----------------+----------------+----------------+
How would I write a query that pulls the status_name in for each column and produce the following result:
+-------------+-------------+-------------+------------+
| Filing Name | Doc1 Status | Doc2 Status | Doc3Status |
+-------------+-------------+-------------+------------+
| John | RECEIVED | NOT_NEEDED | MISSING |
| Mikaela | MISSING | NOT_NEEDED | MISSING |
| Sam | RECEIVED | MISSING | RECEIVED |
+-------------+-------------+-------------+------------+
I'm aware of how to do this when looking up a single field from document_statuses per row, but not multiple. If I only had one column in documents that referred to document_statuses, I'd do a simple JOIN:
SELECT filing_name, status_name
FROM documents d
LEFT JOIN document_statuses ds ON d.doc1_status = ds.status_id
But how do I do that when I need more than one?
You will need to join the statuses table multiple times and then alias the columns in the select clause to be formatted to be what you want. Please note that you have to alias the tables in the join clause so that you can reference the columns in the select clause of the statement.
SELECT filing_name
, ds1.status_name AS 'Doc1 Status'
, ds2.status_name AS 'Doc2 Status'
, ds3.status_name AS 'Doc3 Status'
FROM documents d
LEFT JOIN document_statuses ds1 ON d.doc1_status = ds1.status_id
LEFT JOIN document_statuses ds2 ON d.doc2_status = ds2.status_id
LEFT JOIN document_statuses ds3 ON d.doc3_status = ds3.status_id
You'll need to do three times joins with same table using different aliases for table.
SELECT filing_name, ds.status_name, ds1.status_name,
ds2.status_name FROM documents d
LEFT JOIN document_statuses ds ON d.doc1_status
LEFT JOIN document_statuses ds1 ON d.doc1_status
LEFT JOIN document_statuses ds2 ON d.doc1_status
You can do this:
select t1.filing_name, t2.status_name as doc1_status, t3.status_name as doc2_status, t4.status_name as doc3_status
from filings_table t1
inner join statuses_table t2 on t1.doc1_status_id = t2.status_id
inner join statuses_table t3 on t1.doc2_status_id = t3.status_id
inner join statuses_table t4 on t1.doc3_status_id = t4.status_id

MS Access SQL join only display extra records

I'm trying to display left over records after matching one-to-one rows. How do I display extra/left over records after joining two tables?
Suppose I have two tables, A and B. They both display the the same transactions at the end of the day. However, Table A has more detail about the records but is late in getting updated. Table B, on the other hand, has limited information about transactions but is updated several hours before Table A.
I need a query that can return which records have yet to appear in Table A from Table B.
TABLE A
+-------+-----+---------+----------+---------------------------+
| NAME | ID | AMOUNT | TYPE | PROCESSED TIMESTAMP |
+-------+-----+---------+----------+---------------------------+
| ABC | 123 | -420.07 | PURCHASE | 2018-09-06-08.26.32.000000|
| ABC | 123 | 420.07 | REFUND | 2018-09-06-07.12.18.000000|
| BBC | 456 | -5.00 | PURCHASE | 2018-09-06-10.25.13.000000|
+-------+-----+---------+----------+---------------------------+
TABLE B
+----+----------+---------------------------+
| ID | AMOUNT | RECEIVED TIMESTAMP |
+----+----------+---------------------------+
|123 | -420.07 | 2018-09-05-09.26.15.000000|
|123 | 420.07 | 2018-09-05-08.12.03.000000|
|123 | -420.07 | 2018-09-05-08.40.00.000000|
|456 | -5.00 | 2018-09-05-08.45.00.000000|
+----+----------+---------------------------+
QUERY RESULTS
+----+----------+
| ID | AMOUNT |
+----+----------+
|123 | -420.07 |
+----+----------+
I can manage to find all the records related to the ID that is "off balance" but I need only the specific records that are extra:
SELECT * FROM b
WHERE id
IN
(SELECT d.id AS id
FROM
(SELECT * FROM
(SELECT id, ROUND(SUM(amount),2) AS balance FROM a GROUP BY id) c
RIGHT JOIN
(SELECT id, ROUND(SUM(amount),2) AS balance FROM b GROUP BY id) d
ON c.id = d.id
WHERE c.balance <> d.balance))
Yields...
+----+----------+
| ID | AMOUNT |
+----+----------+
|123 | -420.07 |
|123 | 420.07 |
|123 | -420.07 |
+----+----------+
You need to read up more on joins . There are 3 basic joins which can make life much simpler.
INNER JOIN: First, this is not asked, but the query you have provided for finding off balance items is too complicated. It can be simplified by an inner join.
Inner join is a set operation which will basically get data from both tables (set) which match the condition.
select * from
(
(select id, sum(amount) from a group by id) group_A
INNER JOIN (select id, sum(amount) from b group by id) group_B
ON group_A.id = group_B.id
WHERE group_A.balance != group_B.balance
)
LEFT/RIGHT OUTER JOIN: Left outer join is an operation which will return all the data that is present in both sets and also the data that is in left set but not the right set. Right join is essential same operation on the right set. Important to notice that the extra records pulled here would be null for the side where they do not exist.
Since you want records which are present in table B but not in A, there are multiple ways of achieving this, one would be to get records present in both tables (inner join) and then get all the records in table B but not in the inner join done earlier. Using definition of group_A/group_B from the inner join example.
select id from b where id not in (
select id from group_A INNER JOIN group_B on group_A.id = group_B.id)
Or you can do a right outer join and then using the property of that fields fetched from table A would be coming as null, can filter out the required ID.
select group_B.id from group_A RIGHT OUTER JOIN group_B ON group_A.id = group_B.id
where group_A.id is null
Please use the primary keys on the joins to get the correct results as mentioned by user #ComputerVersteher
I think, you should add PK col.
I can't match data with table A and B, and can't seperate 2 rows at table B.
+----+----------+---------------------------+
| ID | AMOUNT | RECEIVED TIMESTAMP |
+----+----------+---------------------------+
|123 | -420.07 | 2018-09-05-09.26.15.000000|<-
|123 | 420.07 | 2018-09-05-08.12.03.000000|
|123 | -420.07 | 2018-09-05-08.40.00.000000|<-
|456 | -5.00 | 2018-09-05-08.45.00.000000|
+----+----------+---------------------------+
I add new col(deal_no) and made it.
https://www.db-fiddle.com/f/3GfZoQwGhBLf7YWf2RucBF/4
select tmp_B.deal_no, tmp_B.id, tmp_B.amount, tmp_A.deal_no
from tmp_B
left outer join tmp_A
on tmp_A.deal_no = tmp_B.deal_no
where tmp_A.deal_no is null

Use JOIN on multiple columns multiple times

I am trying to figure out the best way to use a JOIN in MSSQL in order to do the following:
I have two tables. One table contains technician IDs and an example of one data set would be as follows:
+--------+---------+---------+---------+---------+
| tagid | techBid | techPid | techFid | techMid |
+--------+---------+---------+---------+---------+
| 1-1001 | 12 | 0 | 11 | 6 |
+--------+---------+---------+---------+---------+
I have another table that stores the names of these technicians:
+------+-----------+
| TTID | SHORTNAME |
+------+-----------+
| 11 | Steven |
| 12 | Mark |
| 6 | Pierce |
+------+-----------+
If the ID of a technician in the first table is 0, there is no technician of that type for that row (types are either B, P, F, or M).
I am trying to come up with a query that will give me a result that contains all of the data from table 1 along with the shortnames from table 2 IF there is a matching ID, so the result would look something like the following:
+--------+---------+---------+---------+---------+----------------+----------------+----------------+----------------+
| tagid | techBid | techPid | techFid | techMid | techBShortName | techPShortName | techFShortName | techMShortName |
+--------+---------+---------+---------+---------+----------------+----------------+----------------+----------------+
| 1-1001 | 12 | 0 | 11 | 6 | Mark | NULL | Steven | Pierce |
+--------+---------+---------+---------+---------+----------------+----------------+----------------+----------------+
I am trying to use a JOIN to do this, but I cannot figure out how to join on multiple columns multiple times to where it would look something like
Select table1.tagid, table1.techBid, table1.techPid, table1.techFid, table1.techMid, table2.shortname
FROM table1
INNER JOIN table2 on //Dont know what to put here
You need to use left joins like this:
Select table1.tagid, table1.techBid, table1.techPid, table1.techFid, table1.techMid,
t2b.shortname, t2p.shortname, t2f.shortname, t2m.shortname,
FROM table1
LEFT JOIN table2 t2b on table1.techBid = t2b.ttid
LEFT JOIN table2 t2p on table1.techPid = t2p.ttid
LEFT JOIN table2 t2f on table1.techFid = t2f.ttid
LEFT JOIN table2 t2m on table1.techMid = t2m.ttid
you just do mutiple left join
select tech.techPid, techPname.SHORTNAME
, tech.techFid, techFname.SHORTNAME
from tech
left join techName as techPname
on tech.techPid = techPname.TTID
left join techName as techFname
on tech.techFid = techFname.TTID

SQL statement - dynamically merging columns from different tables into a single result set

I am not sure this is possible with SQL (say we are executing on DB2) - infact I would say it is not, but thought I would ask some folk who are more experienced in SQL than I am to comment. I have described the problem and what I would like to happen below. Please let me know if you see a way to do this, if not I guess I am down the path of retrieving the data in batches or something like that. Thanks a lot.
MAIN TABLE
| REF_TABLE | RECORD_NO | GROUPID |
| TABLE1 | 1 | BLUE |
| TABLE1 | 2 | BLUE |
| TABLE2 | 3 | GREEN |
| TABLE3 | 4 | BLUE |
| TABLE2 | 5 | GREEN |
| TABLE4 | 6 | BLUE |
TABLE1
| RECORD_NO | NAME | VALUE |
| 1 | NAMEX | RANDOM1 |
| 2 | NAMEY | RANDOM2 |
TABLE2
| RECORD_NO | NAME | VALUE |
| 3 | NAMEB | RANDOM10 |
| 5 | NAMEC | RANDOM9 |
TABLE3
| RECORD_NO | NAME | VALUE |
| 4 | NAMET | RANDOM77 |
TABLE4
| RECORD_NO | NAME | VALUE |
| 6 | NAMET | RANDOM77 |
| 7 | NAMEZ | RANDOM99 |
So I have some criteria for querying MAIN TABLE e.g.
SELECT REF_TABLE, RECORD_NUMBER WHERE GROUPID = 'BLUE'
But I also want to include the appropiate values from the other tables which are referenced via REF_TABLE. So the result would be:
| REF_TABLE | RECORD_NUMBER | NAME | VALUE |
| TABLE1 | 1 | NAMEX | RANDOM1 |
| TABLE1 | 2 | NAMEY | RANDOM2 |
| TABLE3 | 4 | NAMET | RANDOM77 |
| TABLE4 | 6 | NAMET | RANDOM77 |
In this case TABLE1, TABLE3 and TABLE4 have their name and value columns merged into a single result set. The table is of course retrieved from the ref_table column of main table. The list of ref tables in finite, so I could hardcode the table names in SQL statements in the query (to avoid dynamically setting the table name) e.g. IF TABLE1 SELECT FROM SCHEMA.TABLE1 (maybe CASE).
Restructuring the tables is not an option and the number of returned results may be 10000s.
Preferable I would want this all as a single query.
Thanks.
One can also take the UNIONs from Hemal Panya's answer out of the view and into your query...
SELECT record_no, groupid, name, value
FROM main_table INNER JOIN ref_table1 on main_table.record_no = ref_table1.record_no
WHERE main_table.ref_table = 'TABLE1'
UNION ALL
SELECT record_no, groupid, name, value
FROM main_table INNER JOIN ref_table2 on main_table.record_no = ref_table2.record_no
WHERE main_table.ref_table = 'TABLE2'
UNION ALL
etc, etc...
This is probably much faster than tryign to use CASE...
SELECT
main_table.record_no,
main_table.groupid,
CASE main_table.ref_table WHEN 'Table1' THEN Table1.name
WHEN 'Table2' THEN Table2.name
etc, etc
END,
CASE main_table.ref_table WHEN 'Table1' THEN Table1.value
WHEN 'Table2' THEN Table2.value
etc, etc
END
FROM
main_table
LEFT JOIN
Table1
ON main_table.record_no = Table1.record_no
AND main_table.ref_table = 'Table1'
LEFT JOIN
Table2
ON main_table.record_no = Table2.record_no
AND main_table.ref_table = 'Table2'
etc, etc
I would, however, recommend against any of these options. It feels as though your schema is designed against the natural behaviour of SQL. You may either need a new structure, or be better suited to a different environment. Without knowing more details, however, it's impossible to advise on a natural relational structure that would meet your needs without needing this kind of 'conditional join'.
On that basis, I'd be intrigued to know why it is that you are hesitent to use a view to unify your disperate data. It appears, in a vacuum, to be th emost sensible option...
using case is certainly a possibility and should work.
Another option is to
create view REF_TABLE as
select 'TABLE1' as TABLE_NAME, RECORD_NO, NAME, VALUE from TABLE1
UNION select 'TABLE2' as TABLE_NAME, RECORD_NO, NAME, VALUE from TABLE2
...
And then,
select RECORD_NO, GROUPID, NAME, VALUE
from MAIN_TABLE
join REF_TABLE on MAIN_TABLE.REF_TABLE = REF_TABLE.TABLE_NAME and
MAIN_TABLE.RECORD_NO = REF_TABLE.RECORD_NO
etc
EDIT:
Not sure why you want to avoid the view. Given your schema it might be useful elsewhere too, and give you significant performance benefit if you can materialize your views (look it up if you don't know what they are)
The query using case would be something as follows. I am not very clear on sql server case syntax so you will have work on that.
select m.RECORD_NO, m.GROUP_ID,
case when REF_TABLE = 'TABLE1' then t1.NAME, t1.VALUE
else when REF_TABLE = 'TABLE2' then t2.NAME, t2.VALUE
...
end case,
from MAIN_TABLE M
left outer join TABLE1 T1 on M.RECORD_NO = T1.RECORD_NO
left outer join TABLE2 T2 on M.RECORD_NO = T2.RECORD_NO
....

SQL LEFT JOIN help

My scenario: There are 3 tables for storing tv show information; season, episode and episode_translation.
My data: There are 3 seasons, with 3 episodes each one, but there is only translation for one episode.
My objetive: I want to get a list of all the seasons and episodes for a show. If there is a translation available in a specified language, show it, otherwise show null.
My attempt to get serie 1 information in language 1:
SELECT
season_number AS season,number AS episode,name
FROM
season NATURAL JOIN episode
NATURAL LEFT JOIN episode_trans
WHERE
id_serie=1 AND
id_lang=1
ORDER BY
season_number,number
result:
+--------+---------+--------------------------------+
| season | episode | name |
+--------+---------+--------------------------------+
| 3 | 3 | Episode translated into lang 1 |
+--------+---------+--------------------------------+
expected result
+-----------------+--------------------------------+
| season | episode| name |
+-----------------+--------------------------------+
| 1 | 1 | NULL |
| 1 | 2 | NULL |
| 1 | 3 | NULL |
| 2 | 1 | NULL |
| 2 | 2 | NULL |
| 2 | 3 | NULL |
| 3 | 1 | NULL |
| 3 | 2 | NULL |
| 3 | 3 | Episode translated into lang 1 |
+--------+--------+--------------------------------+
Full DB dump
http://pastebin.com/Y8yXNHrH
I tested the following on MySQL 4.1 - it returns your expected output:
SELECT s.season_number AS season,
e.number AS episode,
et.name
FROM SEASON s
JOIN EPISODE e ON e.id_season = s.id_season
LEFT JOIN EPISODE_TRANS et ON et.id_episode = e.id_episode
AND et.id_lang = 1
WHERE s.id_serie = 1
ORDER BY s.season_number, e.number
Generally, when you use ANSI-92 JOIN syntax you need to specify the join criteria in the ON clause. In MySQL, I know that not providing it for INNER JOINs results in a cross join -- a cartesian product.
LEFT JOIN episode_trans
ON episode_trans.id_episode = episode.id_episode
AND episode_trans.id_lang = 1
WHERE id_serie=1
You probably need to move the id_lang = 1 into the LEFT JOIN clause instead of the WHERE clause. Think of it this way... for all of those rows with no translation the LEFT JOIN gives you back NULLs for all of those translation columns. Then in the WHERE clause you are checking to see if that is equal to 1 - which of course evaluates to FALSE.
It would probably be easier if you included your code in the question next time instead of in a link.
Can you try using
LEFT OUTER JOIN
instead of
NATURAL LEFT JOIN