Merging/Joining Multiple Tables SQL - sql

I am working with a database that has 5 tables each with a different number of observations. I include a description of the columns in each table below. As you can see from below, Table 1,2 and 5 have SecurID in common, Table 3 and 4 have Factor in common, and lastly 3 and 5 have BID in common. I need to perform an anlysis of Table 1 vs 2's exposure and return by date. To do this I need to do mulitple merge/joins. I need to join tables 3 and 4 then join them with table 5 and lastly with 1 and 2. What I tried was multiple joins like:
SELECT *
FROM Table3
INNER JOIN Table4 ON Table3.Factor = Table4.Factor
LEFT JOIN Table5 ON Table3.BID = Table5.BID
LEFT JOIN Table1 ON Table5.SecurID = Table1.SecurID
LEFT JOIN Table2 ON Table5.SecurID = Table2.SecurID
My problem is that when I run this query I get a crazy amount of extra observations. Are multiple join functions the most efficient way to combine all these tables? I'm very new to SQL, but each table has an index, which I believe is a faster way to speed up the data retrieval process compared with SELECT.
Table 1 (32,800 Observ.): SecurID, HoldingDate, Weight
Table 2 (2200 Observ.): SecurID, HoldingDate, Weight
Table 3 (808400 Observ.): BID, Factor, Exposure, Date
Table 4 (8000 Observ.): Factor, Return, FactorGrpName
Table 5 (1600 Observ.): SecurID, SecurName, BID

Related

Multiple Joins - Performance

I have three tables:
Table A (approx. 500 000 records)
ID
ID_B
Text
1
10
bla
2
10
blabla
3
30
blablabla
Table B (approx. 100 000 records)
ID
Text
10
blab
20
blaba
30
blabb
Table C (approx. 600 000 records)
ID
ID_A
1
1
2
1
3
2
Now I want to join this three tables:
SELECT A.Text
FROM A
JOIN B ON B.ID = A.ID_B
JOIN C ON C.ID_A = A.ID
I have created a clustered primary key index (ID) and non-clustered index (ID_B) on table A.
According to the execution plan, at the beginning the clustered index is used to join A and C.
Afterwards the result set is sorted on column ID_B and used then in a merge join with B.
Execution Plan
The sort operation is the most expensive one. (about 40% of total costs)
Is there any way to optimize this query in terms of overall performance?
You haven't mentioned if you have any indexes on table B. Perhaps an index on it with the identifier and 'including' any columns you want to output.
Now, from what I gather in the comments, you're really joining to tables b and c primarily as a filter, not because you need to output data from those tables. If that's really the case, you should use exists. You may shy away from subqueries, but the engine knows what to do with exists. You'll see in the plan that it will run a 'semi join'.
select a.text
from a
where exists (select 0 from b where b.id = a.id_b)
and exists (select 0 from c where c.id_a = a.id)

Sql query for multiple tables of SQLite

I have an SQL database (pq) with 3 tables as sample is shown in image. I am trying to achieve below things:
Select only rows with variable P from the MEASUREMENT column in Table 3. I tried below query but it didnt produced the correct output.
select distinct pq_data.READ_TIME,OBS_METER,MEASUREMENT,VALUE from pq_data ORDER BY MEASUREMENT;
Then, fetch the data columns CUST_CLASS, and SOLAR from Table 1 into Table 3 according to OBS_METER id. The OBS_METER column is not available in Table 1 but the it can be obtained from OBS_LOCATION in Table 2.
The expected output of SQL query is Table 3 with additional columns from other tables,such as:
row id READ_TIME OBS_METER OBS_LOCATION MEASUREMENT VALUE CUST_CLASS SOLAR
28/01/2018 2018/01/28 01:55:00 105714 6787 P 284 R F
..........
I searched for existing answers: 1 , 2 but I couldnt able to write a SQL query which will produce above expected output.
Select only rows with variable P from the MEASUREMENT column in Table 3.
select * from pq_data WHERE MEASUREMENT='P';
Then, fetch the data columns CUST_CLASS, and SOLAR from Table 1 into
Table 3 according to OBS_METER id.
select *
from pq_data pd
inner join meter_mapping mm on pd pd.obs_meter=mm.obs_meter
inner join location_mapping lm on mm.obs_location=lm.obs_location
WHERE pd.MEASUREMENT='P'
The expected output of SQL query is Table 3 with additional columns
from other tables:
You did not specify which table is the rowid that you wanted, I assumed that it was from pq_data.
Also, I don't know if an entry on pq_data will always have a match in meter_mapping (and location_maping). If it don't you need to use "left join" (or right).
It would be easier if you used the actual name of the tables in your questions (instead of table 1, 2 and 3).
select pd.rowid, pd.READ_TIME, pd.OBS_METER, mm.OBS_LOCATION, pd.MEASUREMENT, pd.VALUE, lm.CUST_CLASS, lm.SOLAR
from pq_data pd
inner join meter_mapping mm on pd pd.OBS_METER=mm.OBS_METER
inner join location_mapping lm on mm.OBS_LOCATION=lm.OBS_LOCATION
WHERE pd.MEASUREMENT='P'

Get the list for Super and sub types

Am Having the Tables in SQL server as Super and Sub types like below. Now if i have to get list of Furnitures then how can i get the list?
Furniture table:
Id FurnituretypeId NoofLegs
-------------------------------
1 1 4
2 2 4
FurnitureType table:
Id Name
-----------------
1 chair
2 cot
3 table
Chair Table:
Id Name CansSwing CanDetachable FurnitureId
------------------------------------------------------------
1 Chair1 Y Y 1
Cot Table:
Id Name CotType Storage StorageType FurnitureId
-------------------------------------------------------------------
1 Cot1 Auto Y Drawer 2
How can i get the entire furniture list as some of them are chair and some of them are cot. How can i join the these tables with furniture table and get the list?
Hmmm . . . union all and join?
select cc.*, f.*
from ((select Id, Name, CansSwing, CanDetachable,
NULL as CotType, NULL as Storage, NULL as StorageType, FurnitureId
from chairs
) union all
(select Id, Name, NULL as CansSwing, NULL as CanDetachable,
CotType, Storage, StorageType, FurnitureId
from cots
)
) cc join
furniture f
on cc.furnitureid = f.id;
This is a classical learning problem, that's why I'm not giving you the code to solve this but all the insights you need to do so.
You have multiple approaches possible, but I'm describing two simple ones:
1) Use the UNION statement to join two separate queries one for Chair and the other for Cot, bare in mind that both SELECT have to return the same structure.
SELECT
a1,
a2,
etc..
FROM table1 a1
JOIN table2 a2 ON a1.some = a2.some
UNION
SELECT
a1,
a3,
etc..
FROM table1 a1
JOIN table3 a3 ON a1.some = a3.some
2) You can do it all in one SELECT statement using a LEFT JOIN to both tables and and in the select using COALESCE or ISNULL to get the values for one table or the other. In the WHERE condition you have to force one or the other join to be not null.
SELECT
a1,
COALESCE(a2,a3) as col2
FROM table1
LEFT JOIN table2 a2 ON a1.some = a2.some
LEFT JOIN table3 a3 ON a1.some = a3.some
WHERE
a2.some IS NOT NULL
OR a3.some IS NOT NULL
Mapping objects into relational models takes a degree of understanding of what is possible vs. what is wise in an RDBMS. Object oriented database systems tried to go after problems like this (generally without much success) precisely because the problem statement is arguably not the right one.
Please consider just putting all of these in one table. Then use null for the fields that don't really matter for each sub-type. You will likely end up being a lot happier in the end since you can spend less time at runtime doing joins and instead just query the information you need and use indexing on the same table to find the fasted path for each query you want to run.
SELECT * FROM CombinedTable;

Left join - two tables with the same data

Lets say that that I have two simple tables with the following columns and data:
Table 1 Table 2
year month year month
2017 01 2017 01
2016 12 2016 12
The primary key is a composite key that consists of the year and the month.
So a classical left join, gives me all the data in the left table with the matching rows in the right table.
If I do a left join like this:
select
t1.year, t2.month
from
table1 t1
left join table 2 t2 on (t1.year = t2.year and t1.month = t2.month)
Why do I get only two rows?? Shouldn't I get 4 rows??
Tnx,
Tom
A classical left join will give you the number of rows in the "Left Table" (the one in from) multiplied by the number of matches in the "Right Table" (the one in LEFT JOIN in this case), plus all the rows in the LEFT Table that have no match in the first table.
Number of rows in LEFT Table = 2
Number of matches in Right Table = 1
Number of rows in LEFT Table withouth matches = 0
2 x 1 + 0 = 2
Edit: Actually the multiplication is given for each row. Would be something like
Sum (row_i x matches_i) + unmatched
Where row_i is means each row, and matches_i to the matches for the i row in the first table. The difference with this is that each row could have different number of matches (the previous formula is only adapted to your case)
This will result in
1 (row1) x 1 (matches for row 1) + 1 (row2) x 1 (matches for row 2) +
0 (unmatched rows in table 1) = result
1x1 + 1x1 + 0 = result
1 + 1 = 2 = result
If you expected 4 rows maybe you wanted to get a Cartesian Product. As the comment stated, you can use Cross Join in that case
When you join tables together, you're essentially asking the database to combine data from two different tables and display it as a single record. When you perform a left join, you are saying:
Give me all the rows from Table1, as well as any associated data from
Table2 (if it exists).
In this sense, the data from Table2 doesn't represent separate or additional records to Table1 (even though they are stored as separate records in a separate table), it represents associated data. You are linking the data between the tables, not appending rows from each table.
Imagine that Table1 stored people, and Table2 stored phone numbers.
Table1 Table2
+------+-------+--------+ +------+-------+-------------+
| Year | Month | Person | | Year | Month | Phone |
+------+-------+--------+ +------+-------+-------------+
| 2017 | 12 | Bob | | 2017 | 12 | 555-123-4567|
| 2016 | 01 | Frank | | 2016 | 01 | 555-234-5678|
+------+-------+-------+ +------+-------+--------------+
You could join them together to get a list of people and their corresponding phone numbers. But you wouldn't expect to get a combination of rows from each table (two rows of people and two rows of phone numbers).
You will get two rows as both the columns have 2 rows that match exactly the sam and its a composite key.
It will make the same way if you had 4 rows in each you will only get 4 rows in total.
The Left Join takes Table1 (t1) as the Left table.
It searches for and retrieves all values from the Right ie:- from Table 2 (t2) matching the criteria T1.Year&Month = T2.Year&Month (alias GOD/s) as well as the additional join condition T1.Month=T2.Month. The result is that only 2 rows from T1 match the join criteria as well as the additional join criteria
Another takeaway : The AND T1.Month=T2.Month condition on the left join is redundant as the composite GOD key takes care of it explicitly.
cross join returns every row you can make by combining a row from each argument. (inner) join on returns the rows from cross join that satisfy its condition. Ie (inner) join on returns every row you can make that combines a row from each argument and that satisfies its condition.
left join on returns the rows from (inner) join on plus the rows you can make by extending unjoined left argument rows by null for columns of the right argument.
Notice that this is regardless of primary keys, unique column sets, foreign keys or any other constraints.
Here there are 2 rows in each argument so there are 2 X 2 = 4 rows in the cross join. But only 2 meet the condition--the ones where a row is combined with itself.
(If you left join a table with itself where the condition is the conjunction of one or more equalities of the left and right versions of a column and there are no nulls in those columns then every left argument row gets joined with at least itself from the right argument. So there are no unjoined left argument rows. So only the rows of the (inner) join on are returned.)

For MS Access SQL, want to use EXCEPT in Access for three columns in table1 to 1 column in table 2

I have 3 columns in table A. I am trying to design a query that will call out all the values (in the three columns) that do not apepar in the 1 column I have in table B. If it helps to make it more clear, table B is a list of currencies in ISO codes and table A is three columns of currencies being used, I am identifying all those values that are NOT using ISO codes to denote their currency.
Currently, I can't seem to get them all to match to the one column, so I made 2 more columns in table B so I can match them individually. My constraints are, I cannot change table A and I must do this in one query. What I got so far is below.
SELECT m.Currency1, i.ISO_Code, m.Currency2 , i.ISO_Code1, m.Currency3, i.ISO_Code2
FROM A AS m
LEFT JOIN B AS i
ON m.Currency=i.ISO_Code
AND m.Currency2=i.ISO_Code1
AND m.Currency3=i.ISO_Code2
WHERE i.ISO_Code is NULL
OR i.ISO_Code1 is NULL
OR i.ISO_Code2 is NULL;
I wouldn't bother making multiple columns in 'B'. I played with this in SQLFiddle and got it to work.
Something like this:
SELECT
m.Currency1, i.ISO_Code,
m.Currency2, j.ISO_Code AS ISO_Code1,
m.Currency3, k.ISO_Code AS ISO_Code2
FROM A AS m
LEFT JOIN B as i
ON m.Currency1 = i.ISO_Code
LEFT JOIN B as j
ON m.Currency2 = j.ISO_Code
LEFT JOIN B as k
ON m.Currency3 = k.ISO_Code
WHERE
i.ISO_Code IS NULL OR
j.ISO_Code IS NULL OR
k.ISO_Code IS NULL