VB.NET Reportviewer How to make Inner Join work properly - sql

I have 2 tables
tableAssembly, with columns SerialNumber, Brick1SerialNumber, Brick2SerialNumber,DateInserted
tableBricks, with columns SerialNumber, Lot, Weight, DateMeasured
In VB.NET(WinForms) I have been able to get the reportviewer control to work and print out information from both tables and also to enable/disable columns, and apply filters such as LIKE
In case it isn't clear tableAssembly.Brick1SerialNumber = tableBricks.SerialNumber
What I now want to do is when a user prints out a report from tableAssembly, I want them to be able to filter based on Brick1SerialNumber.Lot or Brick2SerialNumber.Lot or Brick1SerialNumber.DateMeasured or Brick2SerialNumber.DateMeasured
I understand I need to INNER JOIN tableAssembly.Brick1SerialNumber = tableBricks.SerialNumber AND tableAssembly.Brick2SerialNumber = tableBricks.SerialNumber
Do I also need to INNER JOIN the other columns from tableBricks to columns in tableAssembly? or does the INNER JOIN of Brick1SerialNumber = SerialNumber and Brick2SerialNumber = Serial make it so I can filter based on .Lot?

There are two ways to approach this. 1) join to tableBricks twice (probably not necessary for this condition) or attach it once, using both foreign keys (works for this condition, but not for all conditions).
Try this query:
SELECT tableAssembly.*
FROM tableAssembly INNER JOIN tableBricks
ON tableAssembly.Brick1SerialNumber = tableBricks.SerialNumber
OR tableAssembly.Brick2SerialNumber = tableBricks.SerialNumber
WHERE tableBricks.Lot = 99 --actually means Brick1.Lot or Brick2.Lot
AND tableBricks.DateMeasured = '1/1/2000'
If you need a specific Lot or DateMeasured for Brick1 and Brick2 (not the same values), then try this query:
SELECT tableAssembly.*
FROM tableAssembly INNER JOIN tableBricks AS tableBricks1
ON tableAssembly.Brick1SerialNumber = tableBricks1.SerialNumber
INNER JOIN tableBricks AS tableBricks2
ON tableAssembly.Brick2SerialNumber = tableBricks2.SerialNumber
WHERE tableBricks1.Lot = 98
AND tableBricks2.Lot = 99
AND tableBricks1.DateMeasured = '1/1/2000'
AND tableBricks2.DateMeasured = '1/2/2000'

Related

Changing old join to new join

I am new to SQL so any help is greatly appreciated. I have a query that seems to be working that has old style joins, and I need to change it to new style joins. the current query is like:
SELECT
STAR.V_DISASTER_DIMENSIONS .DISASTER_NUMBER,
STAR.PA_PROJECT_DIMENSIONS .PW_NUMBER,
STAR.PA_PROJECT_SITE_DIMENSIONS.SITE_NUMBER,
STAR.PA_PROJECT_FACTS .PROJECT_AMOUNT,
STAR.PA_MITIGATION_DIMENSIONS .MITIGATION_ACTIVITY_STATUS
FROM
STAR.V_DISASTER_DIMENSIONS,
STAR.PA_PROJECT_DIMENSIONS,
STAR.PA_PROJECT_SITE_DIMENSIONS,
STAR.PA_MITIGATION_DIMENSIONS,
STAR.PA_PROJECT_FACTS,
STAR.PA_PROJECT_SITE_FACTS
WHERE
( STAR.PA_PROJECT_DIMENSIONS.PA_PROJECT_ID = STAR.PA_PROJECT_FACTS.PA_PROJECT_ID )
AND
( STAR.PA_PROJECT_FACTS.DISASTER_ID = STAR.V_DISASTER_DIMENSIONS.DISASTER_ID )
AND
( STAR.PA_MITIGATION_DIMENSIONS.PA_MITIGATION_ID = STAR.PA_PROJECT_FACTS.PA_PROJECT_ID )
AND
( STAR.PA_PROJECT_SITE_FACTS.PA_PROJECT_ID = STAR.PA_MITIGATION_DIMENSIONS.PA_MITIGATION_ID )
AND
( STAR.PA_PROJECT_SITE_FACTS.DISASTER_ID = STAR.V_DISASTER_DIMENSIONS.DISASTER_ID )
AND
( STAR.PA_PROJECT_SITE_FACTS.PA_PROJECT_ID = STAR.PA_PROJECT_DIMENSIONS.PA_PROJECT_ID )
AND
( STAR.PA_PROJECT_SITE_FACTS.PA_PROJECT_SITE_ID = STAR.PA_PROJECT_SITE_DIMENSIONS.PA_PROJECT_SITE_ID )
My attempt to convert is below. I don't know where to put the extra conditions because they are not 1 to 1 with tables.
FROM
STAR.V_DISASTER_DIMENSIONS
JOIN STAR.PA_PROJECT_SITE_FACTS ON STAR.PA_PROJECT_SITE_FACTS.DISASTER_ID = STAR.V_DISASTER_DIMENSIONS.DISASTER_ID
JOIN STAR.PA_PROJECT_DIMENSIONS ON STAR.PA_PROJECT_SITE_FACTS.PA_PROJECT_ID = STAR.PA_PROJECT_DIMENSIONS.PA_PROJECT_ID
JOIN STAR.PA_PROJECT_SITE_DIMENSIONS ON STAR.PA_PROJECT_SITE_FACTS.PA_PROJECT_SITE_ID = STAR.PA_PROJECT_SITE_DIMENSIONS.PA_PROJECT_SITE_ID
JOIN STAR.PA_MITIGATION_DIMENSIONS ON STAR.PA_PROJECT_SITE_FACTS.PA_PROJECT_ID = STAR.PA_MITIGATION_DIMENSIONS.PA_MITIGATION_ID
JOIN STAR.PA_PROJECT_FACTS ON (
STAR.PA_PROJECT_FACTS .DISASTER_ID = STAR.V_DISASTER_DIMENSIONS.DISASTER_ID AND
STAR.PA_MITIGATION_DIMENSIONS.PA_MITIGATION_ID = STAR.PA_PROJECT_FACTS .PA_PROJECT_ID AND
STAR.PA_PROJECT_DIMENSIONS .PA_PROJECT_ID = STAR.PA_PROJECT_FACTS .PA_PROJECT_ID
)
Change , to INNER JOINs with ON condition:
SELECT
STAR.V_DISASTER_DIMENSIONS.DISASTER_NUMBER,
STAR.PA_PROJECT_DIMENSIONS.PW_NUMBER,
STAR.PA_PROJECT_SITE_DIMENSIONS.SITE_NUMBER,
STAR.PA_PROJECT_FACTS.PROJECT_AMOUNT,
STAR.PA_MITIGATION_DIMENSIONS.MITIGATION_ACTIVITY_STATUS
FROM
STAR.PA_PROJECT_DIMENSIONS PD
INNER JOIN STAR.PA_PROJECT_FACTS PF ON PD.PA_PROJECT_ID=PF.PA_PROJECT_ID
INNER JOIN STAR.V_DISASTER_DIMENSIONS DD ON DD.DISASTER_ID=PF.DISASTER_ID
INNER JOIN STAR.PA_MITIGATION_DIMENSIONS MD ON MD.PA_MITIGATION_ID=PF.PA_PROJECT_ID
INNER JOIN STAR.PA_PROJECT_SITE_FACTS PSF ON PSF.PA_PROJECT_ID=MD.PA_MITIGATION_ID
AND PSF.DISASTER_ID=DD.DISASTER_ID
AND PSF.PA_PROJECT_ID=PD.PA_PROJECT_ID
INNER JOIN STAR.PA_PROJECT_SITE_DIMENSIONS PSD ON PSD.PA_PROJECT_SITE_ID=PSF.PA_PROJECT_SITE_ID
Select * from
a,b
where a.z = b.y
would be written as
Select * from
a
INNER JOIN
b
ON a.z = b.y
It is easy. Just start with the facts table and join related tables on foreign key = key.
First of all you should use table aliases to get the query more readable. Also use some lowercase letters, too.
Then just write the table names (or the aliases) on paper and draw a line for each condition from one table to the other. Then pick one table to start with, e.g. pa_project_site_dimensions which is only linked to one table.
SELECT
dd.disaster_number,
pd.pw_number,
psd.site_number,
psf.project_amount,
md.mitigation_activity_status
FROM star.pa_project_site_dimensions psd
JOIN star.pa_project_site_facts psf ON psf.pa_project_site_id = psd.pa_project_site_id
JOIN star.v_disaster_dimensions dd ON dd.disaster_id = psf.disaster_id
JOIN star.pa_mitigation_dimensions md ON md.pa_mitigation_id = psf.pa_project_id
JOIN star.pa_project_dimensions pd ON pd.pa_project_id = psf.pa_project_id
JOIN star.pa_project_facts pf ON pf.disaster_id = dd.disaster_id
AND pf.pa_project_id = md.pa_mitigation_id
AND pf.pa_project_id = pd.pa_project_id
;
However, this is a strange query. First of all there is no limiting condition, you simply join all records, rather than retrieving data for, say, one particular project.
Moreover, you deal with several dimensions. Obviously a project has facts (pa_project_facts) and dimensions (pa_project_dimensions). With 5 facts and 3 dimensions you'd get 15 rows with all their combinations. Then there are also project sites it seems (maybe a table pa_project_sites we don't see in the query). Either that project site has facts on its own (pa_project_site_facts) that you also combine with all rows, or a project site is linked to a project fact via pa_project_site_facts, but then pa_project_facts wouldn't have to be joined by pa_project_id only, but also by some fact ID.
Also this looks strange: md.pa_mitigation_id = psf.pa_project_id. Is a mitigation the same as a project?
So after all have a look at all columns that need to be joined on. Think about how the tables are related and if you are not building combinations that make no sense.

Better method for returning multiple rows using AND Statement

I was just wondering if there was a better way of processing the statement below, as I feel this is quite limited.
SELECT Bill_of_Materials.BM_Assembly
, Bill_of_Materials.BM_Part_No
, Bill_of_Materials.BM_Qty
, Bill_of_Materials_1.BM_Part_No
, Bill_of_Materials_1.BM_Qty
, Bill_of_Materials_2.BM_Part_No
, Bill_of_Materials_2.BM_Qty
, Stock_File.STK_Description
FROM ((Bill_of_Materials INNER JOIN Bill_of_Materials AS Bill_of_Materials_1 ON Bill_of_Materials.BM_Assembly = Bill_of_Materials_1.BM_Assembly)
INNER JOIN Stock_File ON Bill_of_Materials.BM_Assembly = Stock_File.STK_Part_No)
INNER JOIN Bill_of_Materials AS Bill_of_Materials_2 ON Bill_of_Materials_1.BM_Assembly = Bill_of_Materials_2.BM_Assembly
WHERE (((Bill_of_Materials.BM_Part_No)="161070")
AND ((Bill_of_Materials.BM_Qty)=2)
AND ((Bill_of_Materials_1.BM_Part_No)="161317")
AND ((Bill_of_Materials_1.BM_Qty)=2)
AND ((Bill_of_Materials_2.BM_Part_No)="410382"));
I am trying to run several AND statements on the same field, but I need to return multiple rows. Now depending on how many AND statements I want to run depends on how many times I need to join the table, but I really want this to be more dynamic.
I am trying to find a 'Finished Item' by matching several componets which are used in the build (hence the multiple AND statements.
Any suggestions would be great.
You may simplify the query like this :
SELECT Bill_of_Materials.BM_Assembly,
Bill_of_Materials.BM_Part_No,
Bill_of_Materials.BM_Qty,
Bill_of_Materials_1.BM_Part_No,
Bill_of_Materials_1.BM_Qty,
Bill_of_Materials_2.BM_Part_No,
Bill_of_Materials_2.BM_Qty,
Stock_File.STK_Description
FROM Bill_of_Materials
INNER JOIN Bill_of_Materials AS Bill_of_Materials_1
ON Bill_of_Materials.BM_Assembly = Bill_of_Materials_1.BM_Assembly
AND Bill_of_Materials_1.BM_Part_No = "161317"
AND Bill_of_Materials_1.BM_Qty = 2
INNER JOIN Bill_of_Materials AS Bill_of_Materials_2
ON Bill_of_Materials_1.BM_Assembly = Bill_of_Materials_2.BM_Assembly
AND Bill_of_Materials_2.BM_Part_No = "410382"
INNER JOIN Stock_File
ON Bill_of_Materials.BM_Assembly = Stock_File.STK_Part_No
WHERE Bill_of_Materials.BM_Part_No = "161070"
AND Bill_of_Materials.BM_Qty = 2;
With restritions inside the join conditon, you are reducing the numbers of records for each join.

SumIF Access - Multiple tables

I am following the question I asked here: SumIF in SQL Access
I have 3 tables [Broker] , [OPT], [TRS]. [Broker] have 2 fields BRKR_CODE, Status and [OPT] and [TRS] Have 5 same fields BRKR1, BRKR2, Date, COM_BRK1, COM_BRKR2
OPT.BRKR1, OPT.BRKR2, TRS.BRKR1, TRS.BRKR2 are linked to Broker.BRKR_CODE and can be equal.
I want to write this query.... If Broker.Status="Active" then Select Broker.BRKR_CODE
and then for each Broker.BRKR_CODE (for example "CB") do the Sum of OPT.COM_BRKR1 when OPT.BRKR1="CB" + Sum of OPT.COM_BRKR2 when OPT.BRKR2="CB" and do the Sum of TRS.COM_BRKR1 when TRS.BRKR1="CB" + Sum of TRS.COM_BRKR2 when TRS.BRKR2="CB"
I wrote this code using the answer I got in the previous question... but still have syntax issue... basically I want to have an array with 3 column BRKR_CODE, OPT_Tot, TRS_Tot
SELECT Broker.BRKR_CODE,
Sum(OPT.COM_BRKR1)+ Sum(OPT.COM_BRKR2) AS OPT_Tot,
Sum(TRS.COM_BRKR1)+ Sum(TRS.COM_BRKR2) AS TRS_Tot
FROM Broker
INNER JOIN OPT
ON (Broker.BRKR_CODE = OPT.BRKR2) OR (Broker.BRKR_CODE = OPT.BRKR1)
INNER JOIN TRS
ON (Broker.BRKR_CODE = TRS.BRKR2) OR (Broker.BRKR_CODE = TRS.BRKR1)
WHERE Broker.Status = "Active"
GROUP BY Broker.BRKR_CODE
You should try to make this query in the designer (just to get the base joins right). You'll see Access does some different stuff with parentheses that other SQL engines don't do.
You need to wrap each set of joins in parentheses
SELECT Broker.BRKR_CODE,
Sum(OPT.COM_BRKR1)+ Sum(OPT.COM_BRKR2) AS OPT_Tot,
Sum(TRS.COM_BRKR1)+ Sum(TRS.COM_BRKR2) AS TRS_Tot
FROM (Broker
INNER JOIN OPT
ON (Broker.BRKR_CODE = OPT.BRKR2) OR (Broker.BRKR_CODE = OPT.BRKR1))
INNER JOIN TRS
ON (Broker.BRKR_CODE = TRS.BRKR2) OR (Broker.BRKR_CODE = TRS.BRKR1)
WHERE Broker.Status = "Active"
GROUP BY Broker.BRKR_CODE

SQL Query that sorts information into two new columns based on a third column

I have a table that stores basic site information, another one that stores the site address, and a third table for the phone. My phone table contains phone numbers, and the type of number.
What I want to do is get my site information, and the main contact number and fax number. So far, my statement looks like this:
SELECT site.isiteid,
site.iclientid,
csitecode,
csitename,
binactive,
caddress1,
caddress2,
ccity,
cstateid,
czip,
icountryid,
cattention,
cemail,
cnumber,
cextension
FROM dbo.site
INNER JOIN dbo.address
ON dbo.site.isiteid = dbo.address.isiteid
AND (site.isiteid = 2)
LEFT JOIN dbo.phone
ON dbo.site.isiteid = dbo.phone.isiteid
AND (dbo.phone.iphtypeid = 1)
This gets me all of the information that I need except for the fax number (dbo.phone.iphtypeid=3). Is there a way to add another column to the result called [fax], and populate it when site.isiteid=phone.isiteid AND phone.iphtypeid=3? Thus, the last 4 columns returned would be [cemail][cnumber][cextension][cfax].
RESOLVED
Thank you to all three who answered. All the answers were similar, so I selected the one that had the most detailed explanation. I did need to add the table name to both cnumber references and cextension to avoid ambiguity. Thank you for the responses!
Add another JOIN clause
LEFT JOIN dbo.phone f
ON dbo.site.isiteid = f.isiteid
AND f.iphtypeid = 3
You would then add f.cfax to the SELECT list.
It might also be good to give the other tables aliases so you can distinguish which columns are coming from which tables.
Yes, you can do this by adding another join to dbo.phone. To distinguish between the two uses, you will need to give the second join an alias. So, something like:
SELECT site.isiteid,
site.iclientid,
csitecode,
csitename,
binactive,
caddress1,
caddress2,
ccity,
cstateid,
czip,
icountryid,
cattention,
cemail,
phone.cnumber,
phone.cextension,
phone_fax.cnumber AS cfax
FROM dbo.site
INNER JOIN dbo.address
ON dbo.site.isiteid = dbo.address.isiteid
AND (site.isiteid = 2)
LEFT JOIN dbo.phone
ON dbo.site.isiteid = dbo.phone.isiteid
AND (dbo.phone.iphtypeid = 1)
LEFT JOIN dbo.phone AS phone_fax
ON dbo.site.isiteid = phone_fax.isiteid
AND (phone_fax.iphtypeid = 3)
You could do something like, even though I'm not sure of how you're tables are defined.
SELECT site.isiteid,
site.iclientid,
csitecode,
csitename,
binactive,
caddress1,
caddress2,
ccity,
cstateid,
czip,
icountryid,
cattention,
cemail,
cnumber,
cextension,
CASE WHEN C.iphtypeid = 3 THEN C.cnumber ELSE NULL END [cfax]
FROM dbo.site A
INNER JOIN dbo.address
ON dbo.site.isiteid = dbo.address.isiteid
AND (site.isiteid = 2)
LEFT JOIN dbo.phone C
ON A.isiteid = C.isiteid

Conditional SQL JOIN based on column contents

I have a table, event_sessions that contains a session_submitted_by ID and a session_submitter_type. I need to JOIN session_submitted_by to one of two different tables, based on the contents of session_submitter_type.
I can't just do an LEFT OUTER JOIN on both tables and choose whichever returns content because both tables may contain an ID match.
Here is my improper SQL/pseudo-code that shows what I'm trying to accomplish:
SELECT es.event_session_id,
subu.first_name + ' ' + subu.last_name as submitted_by_name,
subu.email as submitter_email
FROM event_session es
CASE WHEN es.session_submitter_type = 'speaker'
THEN
LEFT OUTER JOIN speakers subu
ON subu.speaker_id = es.session_submitted_by
ELSE
LEFT OUTER JOIN users subu
ON subu.user_id = es.session_submitted_by
END
Any suggestions how to code this without having to resort to a UNION?
Interesting question. I would do it like so:
SELECT es.event_session_id,
coalesce(spk.first_name, usr.first_name)
+ ' ' + coalesce(spk.last_name, usr.last_name) as submitted_by_name,
coalesce(spk.email, usr.email) as submitter_email
FROM event_session es
LEFT OUTER JOIN speakers spk
ON es.session_submitter_type = 'speaker' and spk.speaker_id = es.session_submitted_by
LEFT OUTER JOIN users usr
ON es.session_submitter_type <> 'speaker' and usr.user_id = es.session_submitted_by
You basically use two left outer joins, and one only one of them is ever going to be active for any given row of event_session.
Note: If session_submitter_type is nullable then you need to add a NULL check in the second join to maintain the semantics of your pseudo code.