Table Join Distinct Field - vb.net

The problem which I am having is joining two tables. One table contains all the generic data and the second table contains old fields which have been given specific values. The exemplary tables below should help to clarify my setup.
Table 1 (Generic Data)
ParaIndex ParaName ParaDefault
1 Cat 15
2 Fish 8
3 Dog 3
Table 2 (Specific Data)
Project ParaIndex ParaValue
John 1 6
John 2 7
Alan 3 9
The goal then is to join these tables to get a single table:
Table 3 (Table Join on ParaIndex for 'John')
ParaName ParaIndex ParaValue ParaDefault
Cat 1 6 15
Fish 2 7 8
Dog 3 3
So Table 3 would return all rows from Table 1 but would only show values for ParaValue where they are not empty. E What I have tried so far is a combination of changing the join type, distinct select, group by, select subqueries, and suggestions mentioned in other posts.
The end goal is then to use this query in vb.net as par of a form.
The closest which I have gotten is to return the requested data in table 3, but it would exclude rows which are not requested (e.g. if the query is for 'John' it would then exclude the parameters marked by 'Alan' which is 3-Dog in this case).
SELECT t1.ParaName, t1.ParaIndex, t2.ParaValue, t1.ParaDefault
FROM Table1 AS t1LEFT OUTER JOIN Table2 AS t2
ON t1.ParaIndex = t2.ParaIndex
WHERE (((t2.ParaIndex) is null) OR t2.Project = 'John')

You have to use a LEFT OUTER JOIN:
SELECT t1.ParaName,
t1.ParaIndex,
COALESCE(CAST(t2.ParaValue AS VARCHAR(10), '') AS ParaValue,
t1.ParaDefaule,
FROM dbo.Table1 t1
LEFT OUTER JOIN dbo.Table2 t2
ON t1.ParaIndex = t2.ParaIndex
WHERE t2.Project = 'John'
ORDER BY t1.ParaIndex

Related

Join table using column value as table name

Is it possible to join a table whereby the table name is a value in a column?
Here is a TABLE called food:
id food_name price_table pricing_reference_id
1 | 'apple' | 'daily_price' | 13
2 | 'banana' | 'monthly_price' | 13
3 | 'hotdog' | 'weekly_price' | 17
4 | 'sandwich' | 'monthly_price' | 9
There are three other tables (pricing tables): daily_price, weekly_price, and monthly_price tables.
Side note: Despite their names, the three pricing tables display vastly different kinds of information, which is why the three tables were not merged into one table
Each row in the food table can only be joined with one of the three pricing tables at most.
The following does not work -- it is just to illustrate what I am trying to get at:
SELECT *
FROM food
LEFT JOIN food.price_table ON food.pricing_reference_id = daily_price.id
WHERE id = 1;
Obviously the query does not work. Is there any way that the name of the table in the price_table column could be used as the table name in a join?
I would suggest left joins:
select f.*,
coalesce(dp.price, wp.price, mp.price) as price
from food f left join
daily_price dp
on f.pricing_reference_id = dp.id and
f.pricing_table = 'daily_price' left join
weekly_price wp
on f.pricing_reference_id = wp.id and
f.pricing_table = 'weekly_price' left join
monthly_price mp
on f.pricing_reference_id = mp.id and
f.pricing_table = 'monthly_price' ;
For the columns you reference, you need to use coalesce() to combine the results from the three tables. You say that the tables have different data, so you would need to list the columns separately.
The main reason I recommend this approach is performance. I think the left joins should be faster than any solution that uses union all.
Could you get your expected result using by a derived table with UNION SELECT which has a column of each table name?
SELECT *
FROM food
LEFT JOIN
(
SELECT 'daily_price' AS price_table, * FROM daily_price
UNION ALL SELECT 'monthly_price', * FROM monthly_price
UNION ALL SELECT 'weekly_price', * FROM weekly_price
) t
ON food.price_table = t.price_table AND
food.pricing_reference_id = t.id
ORDER BY food.id;
dbfiddle

SQL Multiple columns on one table joined column from other table

I've been trying to run an SQL query but haven't been having much luck. No matter what I do I can't seem to get it to run the way I need it to. I am able to get the tables to join and get the names across, but I can't get the query output I'm looking for.
I have two tables, one table has 3 columns for 1st, 2nd, and 3rd gate techs to be entered. The second table has a list of gate techs we use, the ID for the techs is the primary key.
What I'm looking for is an SQL statement that will get the the keys from the gate table. Example would be Gate Table ID 2 would get 2, 2, 1, then join with the tech table and return the tech names instead of the key.
I can one to work if I do the following, but cant get 3 separate columns with the data.
SELECT TName
FROM TechTable
INNER JOIN GateTable
ON GateTabe.Gate1=TechTable.ID
WHERE ID = 3
-
GateTable
ID Gate1 Gate2 Gate3
1 1 2 3
2 2 2 1
3 4 2 1
-
TechTable
ID TName
1 Tech1
2 Tech2
3 Tech3
4 Tech4
Query Result
ID Gate1 Gate2 Gate3
1 Tech1 Tech2 Tech3
2 Tech2 Tech2 Tech1
3 Tech4 Tech2 Tech1
join the techTable thrice, once for each different gate.
SELECT g.id,t1.TName as gate1,t2.TName as gate2,t3.TName as gate3
FROM GateTable g
INNER JOIN TechTable t1 ON g.Gate1=t1.ID
INNER JOIN TechTable t2 ON g.Gate2=t2.ID
INNER JOIN TechTable t3 ON g.Gate3=t3.ID
SELECT gt.ID, t1.TName as Gate1, t2.TName as Gate2, t3.TName as Gate3
FROM GateTable gt
LEFT JOIN TechTable t1
ON gt.Gate1=t1.ID
LEFT JOIN TechTable t2
ON gt.Gate2=t2.ID
LEFT JOIN TechTable t3
ON gt.Gate3=t3.ID
You can use INNER JOIN too but it gives you only mapped columns. In your example you specified Gate1 value as 4, but it is not there in TechTable. In this case, INNER JOIN skips that value. But LEFT JOIN would give you mapped values and null for the not available mapping.
You can use where clause if you need specific GateID.

SQL: Unable to find a join or union to produce the following table

A Pupil table with { ID, LastName}
a Subject Table with {ID, SubjectName}
and a Report Table with {ID, PupilID, SubjectID, Grade}
There is a one-to-many relationship between Pupil and Report Tables, and Subject and Report Tables.
I want to generate a table like this for say subjectID = 1
Pupil.ID Pupil.LastName SubjectID Grade
1 --------------Smith ---------- 1 ------------B
2 --------------Jones ---------- 1 ------------NULL
3 -------------Weston ----------1 ------------NULL
4 -------------Knightly ---------1 -----------A
The problem is that the Report table would contain just 2 entries for subject 1:
PupilID SubjectID Grade
----1------- 1 ----------- B
----4------- 1 ----------- A
Left joins don't seem to work since there are only 2 entries in the report table for subject 1
SAMPLE DATA
{Pupil Table}
ID LastName
1 ...Smith
2 ...Jones
3 ...Weston
4 ...Knightly
{Subject Table}
ID SubjectName
1 ....Maths
2 ....Physics
3 ....Chemistry
{Report Table}
ID PupilID SubjectID Grade
1 .......1 ..........1 ..........B
2 .......4 ..........1 ..........A
When I do a search on SubjectID = 1 I want the table:
Pupil.ID .......Pupil.LastName ........SubjectID ...........Grade
1 --------------Smith ---------- 1 ------------B
2 --------------Jones ---------- 1 ------------NULL
3 -------------Weston ----------1 ------------NULL
4 -------------Knightly ---------1 -----------A
Access doesn't do subqueries very easily, so everything gets crammed into the FROM clause with a series of wrapped parentheses. Based on your sample data and my fighting Access to stop being unnecessarily difficult, I came up with this:
SELECT ps.Pupil_ID, ps.LastName, ps.Subject_ID, r.Grade
FROM (SELECT * FROM (SELECT ID AS Pupil_ID, LastName FROM Pupil) p,
(SELECT DISTINCT ID AS Subject_ID FROM Subject)) ps
LEFT JOIN REPORT r ON r.PupilID = ps.Pupil_ID AND r.SubjectID = ps.Subject_ID
ORDER BY Pupil_ID, Subject_ID;
The subquery "ps" is a cartesian join of the Pupil and Subject table views that I specified. At this point, your query would look like this:
(LastName column not shown for clarity)
StudentID|SubjectID
1 1
1 2
1 3
2 1
2 2
2 3
3 1
3 2
3 3
Now, using that Cartesian join subquery (pupilstudent -> ps), I use a LEFT JOIN to assign the Report table to each unique student's ID and subject ID. Therefore, if a student did not take a particular class, there will be a NULL value in the final result.
I tested this in Access using your sample data and it works on my machine.
Also as a note, it is poor practice to have a field called just ID in each table (e.g. in the Pupil table, ID becomes PupilID). This makes it much easier to use, and it self documents.
Cross join pupil and subject tables and left join result to report table
What you need is a cross join:
SELECT Pupil.ID, Pupil.LastName, SubjectID, Grade FROM
Pupil, Subject LEFT JOIN Report ON Subject.ID=Report.SubjectID
WHERE Subject.ID=1
To combine every pupil with every (or with a particular) subject, use cross join; Then use left join to get the corresponding grades:
select *
from pupil p cross join (select * from subject where id = 1) s
left join report on subjectId = s.id and pupilId = p.id

SQL replace values in selection many columns

I have two tables:
Table Users
UserId Name
1 John
2 Alice
3 Tom
4 Charles
....
23120 Bob
and
Table Clients
Id Name1 Name2 Name3 .... Name2345
1 1 3 450 4
2 2 17 33 1
...
15302920 44 231 5 7
I would like to make a SQL query where for
Clients.Id = 1
the results are like:
Id Name1 Name2 Name3 ... Name2345
1 John Tom Bill Charles
My clients table has thousands of columns and I try to find a way to replace the values in all columns of the selected results (except the ID column) without thousands of joins.
I know that I can use a query of the following type (but I would like to avoid thousands of joins):
SELECT a.ID,
b.name name1,
c.name name2,
d.name name3
FROM clients a
INNER JOIN users b
ON a.name1 = b.userID
INNER JOIN users c
ON a.name2 = c.userID
INNER JOIN users d
ON a.name3 = d.userID
WHERE a.ID = 1
In addtion:
I can't change the data/structure of the "Clients" table but I can change the "Users" table as necessary.
I can't duplicate the "Clients" table as well since it very large and changes rapidly.
The "Clients" table has thousands of columns and millions of rows, but the selected part is always a small enough subset of the table.
Is it possible?
There is no simple query to achieve this since SQL is fundamentally flexible in rows (vertically) and rigid in columns. This is the closest I came up with:
select c.id,
(select name from dbo.users where UserId = c.name1),
(select name from dbo.users where UserId = c.name2),
(select name from dbo.users where UserId = c.name3),
(select name from dbo.users where UserId = c.name4)
from clients c

SQl Left Join Query

These are the tables that i have(I got this):
table building: b_id(key relation with table build-works b_id):1 2 3
field1: buildingA, buildingB,
buildingC
table build-works: b_id:1 1 2 3 3 3
w_id: 1 2 1 1 2 3
table works: w_id(key relation with table build-works w_id): 1 2 3 4
field1: electricity, sanitary, shell,
roofing
Now I want to know the works per building?
How can i do this with sql, and can you give my the example also with zend_db?
Thanks
using left joins since its in the title
SELECT *
FROM building b
LEFT JOIN buildworks bw
ON b.b_id = bw.b_od
LEFT JOIN works w
ON bw.w_id = w.w_id
Assuming b_id is the primary key for building, (b_id, w_id) is key for build_works, and w_id is key for works you can do it as follows:
Project_building.field1,works.field1(building JOIN build_works JOIN works)
Note that you have to rename field1 of works to something else when doing JOIN.
Also note that this might not be the most efficient way to do it.