Changing old join to new join - sql

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.

Related

How to do multiple left joins in SQL Server SQL Query

I'm trying to perform the query below on SQL Server:
SELECT
[dbo].[Machine].[MachineID],
[dbo].[Machine].[CompanyID],
[dbo].[Company].[AccountRef],
[dbo].[Machine].[ProductTypeID],
[dbo].[Machine].[SerialNo],
[dbo].[Machine].[InstallationDate],
[dbo].[Machine].[SalesTypeID],
[dbo].[SalesType].[SalesType],
[dbo].[Machine].[LeasingCompanyID],
[dbo].[LeasingCompany].[Name],
[dbo].[Machine].[QuarterlyRentalCost],
[dbo].[Machine].[Term],
[dbo].[Machine].[ExpiryDate],
[dbo].[Machine].[Scales],
[dbo].[Machine].[Chips],
[dbo].[Machine].[ContractTypeID],
[dbo].[ContractType].[ContractType],
[dbo].[Machine].[ContractCost],
[dbo].[Machine].[InvoiceDate],
[dbo].[Machine].[ServiceDueDate],
[dbo].[Machine].[ServiceNotes],
[dbo].[Machine].[modelID],
[dbo].[Machine].[Model],
[dbo].[Machine].[IMP_Machine Reference],
[dbo].[Machine].[Smart]
FROM
[dbo].[Machine], [dbo].[Company], [dbo].[SalesType], [dbo].[LeasingCompany], [dbo].[ContractType]
LEFT JOIN
[dbo].[Machine] as A ON A.[CompanyID] = [dbo].[Company].[CompanyID]
LEFT JOIN
[dbo].[Machine] as B ON B.[SalesTypeID] = [dbo].[SalesType].[SalesTypeID]
LEFT JOIN
[dbo].[Machine] as C ON C.[LeasingCompanyID] = [dbo].[LeasingCompany].[LeasingCompanyID]
LEFT JOIN
[dbo].[Machine] as D ON D.[ContractTypeID] = [dbo].[ContractType].[ContractTypeID] ;
But for some reason that i cannot see for the life of me, the destination column name in the bottom 3 join statements is reporting "The multi part identifier could not be bound".
Could anyone assist please?
Many Thanks,
You were pretty close, for readability, you dont need the extensive [dbo].[table] all over. You can define it once in the from clause with an alias, then use that alias the rest of the way through. Also, make the alias make sense to the context of the table as you will see in this below. LeasingCompany lc, SalesType st, etc.
Also, I try to have indented so I always know the first table of the join relationship and the JOIN indented on where it is being joined to. Then I keep the orientation of the from/to table aliases the same context.
Since the machine table is used once and joined to 4 different lookup tables, you can reuse the same "m" alias to each underlying. Think of a tree and branches. The root tree is your "Machine", and all the branches are the lookups.
SELECT
m.MachineID,
m.CompanyID,
c.AccountRef,
m.ProductTypeID,
m.SerialNo,
m.InstallationDate,
m.SalesTypeID,
st.SalesType,
m.LeasingCompanyID,
lc.LeasingCompany.Name,
m.QuarterlyRentalCost,
m.Term,
m.ExpiryDate,
m.Scales,
m.Chips,
m.ContractTypeID,
ct.ContractType,
m.ContractCost,
m.InvoiceDate,
m.ServiceDueDate,
m.ServiceNotes,
m.modelID,
m.Model,
m.IMP_Machine Reference,
m.Smart
FROM
Machine m
LEFT JOIN Company c
ON m.CompanyID = c.CompanyID
LEFT JOIN SalesType st
ON m.SalesTypeID = st.SalesTypeID
LEFT JOIN LeasingCompany lc
ON m.LeasingCompanyID = lc.LeasingCompanyID
LEFT JOIN ContractType ct
ON m.ContractTypeID = ct.ContractTypeID ;

Nesting multiple same select queries and reuse without second round trip to database

I am having a rows with two different IDs in database. Now I am trying to show two different data columns in one row, I tried something like this:
SELECT
[dbo].[fnHexToNumber]([Participant].[Stake]) AS [PlayerStake],
(SELECT [dbo].[fnHexToNumber]([Stake])
FROM [dbo].[Participant_Complete]
WHERE [ParticipantId] = [Fold].[HouseParticipantId]) AS [HouseStake],
([dbo].[fnHexToNumber]([Participant].[Stake]) + [dbo].[fnHexToNumber]([C].[RunningWinLoss])) AS [PlayerStakeAfterRound],
(SELECT [dbo].[fnHexToNumber]([Stake])
FROM [dbo].[Participant_Complete]
WHERE [ParticipantId] = [Fold].[HouseParticipantId]) - [dbo].[fnHexToNumber]([C].[RunningWinLoss]) AS [HouseStakeAfterRound]
FROM
[dbo].[Round_Complete] AS [C]
INNER JOIN
[dbo].[Fold_Complete] AS [Fold] ON [Fold].[Id] = [C].[Id]
INNER JOIN
[dbo].[Participant_Complete] AS [Participant] ON [Participant].[ParticipantId] = [Fold].[PlayerParticipantId]
This works, but as you can see it will do two trips to database for same nested select. How can I make this only one round trip?
You are referring to the subqueries. That is not a "round trip to the database", which usually refers to an application calling a query.
All the square braces make the query hard to read, but you can fix this using apply:
SELECT [dbo].[fnHexToNumber](p.[Stake]) AS PlayerStake,
h.HouseStake,
([dbo].[fnHexToNumber](p.[Stake]) + [dbo].[fnHexToNumber]([C].RunningWinLoss)) AS PlayerStakeAfterRound,
(h.HouseStake - [dbo].fnHexToNumber(C.RunningWinLoss)) AS HouseStakeAfterRound
FROM [dbo].[Round_Complete] c JOIN
[dbo].[Fold_Complete] f
ON f.[Id] = c.[Id] JOIN
[dbo].[Participant_Complete] pc
ON px.[ParticipantId] = f.[PlayerParticipantId] OUTER APPLY
(SELECT [dbo].[fnHexToNumber]([Stake]) as HouseStake
FROM [dbo].[Participant_Complete] pch
WHERE pch.ParticipantId = f.HouseParticipantId
) h
Just join the same table a second time instead of pulling the data as sub-queries.
Also, you only need brackets around names if the names contain a space (which is bad practice in general). If the names don't have a space, the brackets are totally extraneous.
SELECT
dbo.fnHexToNumber(Participant.Stake) AS PlayerStake,
dbo.fnHexToNumber(p.Stake) as HouseStake,
(dbo.fnHexToNumber(Participant.Stake) + dbo.fnHexToNumber(C.RunningWinLoss)) AS PlayerStakeAfterRound,
dbo.fnHexToNumber(p.Stake) - dbo.fnHexToNumber(c.RunningWinLoss) as HouseStakeAfterRound
FROM dbo.Round_Complete AS C
INNER JOIN dbo.Fold_Complete AS Fold
ON Fold.Id = C.Id
INNER JOIN dbo.Participant_Complete AS Participant
ON Participant.ParticipantId = Fold.PlayerParticipantId
INNER JOIN dbo.Participant_Complete AS p
ON p.ParticipantId = Fold.HouseParticipantId

VB.NET Reportviewer How to make Inner Join work properly

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'

SQL Need advice how to add timestamp to this query

I have this code:
select Users.phoneMac, Users.apMac, Locations.Lon, Locations.Lat
from Locations, Users
inner join (
select u.phoneMac, max(u.strenght) as most
from Users u, Locations l
where u.apMac = l.apMac
group by u.phoneMac
) as ij on ij.phoneMac=Users.phoneMac and Users.strenght = ij.most
where Locations.apMac = Users.apMac;
It worked for me fine but when I added more data to users table this query calculated results from all the data and I wanted to get results just from latest data. So I added timestamp to Users table.
So can you help me fix this code so it first take only data from latest timestamp for every user(users.phoneMac)(there can be more then 1 row of data for same phoneMac) and then do the rest of calculations.
You're already picking the max value of the "strenght" field and joining on that, so why not use the same approach again for your timestamp field? Something like:
SELECT Users.phoneMac, Users.apMac, Locations.Lon, Locations.Lat
FROM Locations
INNER JOIN Users
ON Users.apMac = Locations.apMac
INNER JOIN (
SELECT u.phoneMac, max(u.strenght) AS most
FROM Locations l
INNER JOIN Users u ON u.apMac = l.apMac
GROUP BY u.phoneMac) AS ij
ON ij.phoneMac = Users.phoneMac
AND Users.strenght = ij.most
INNER JOIN (
SELECT u2.phoneMac, max(u2.timestampfield) AS latest
FROM Locations l2
INNER JOIN Users u2 ON u2.apMac = l2.apMac
GROUP BY u2.phoneMac) AS ijk
ON ijk.phoneMac = Users.phoneMac
AND Users.timestampfield = ij.latest;
(By the way, using the old join syntax with comma and the WHERE clause makes it harder to understand the logic, and occasionally makes the logic wrong. The new join syntax with ON is really a lot better.)

SQL query for filtering data

I`m working on some sql queries to get some data out of a table; I have made 2 queries for the
same data but both give another result. The 2 queries are:
SELECT Samples.Sample,
data_overview.Sample_Name,
data_overview.Sample_Group,
data_overview.NorTum,
data_overview.Sample_Plate,
data_overview.Sentrix_ID,
data_overview.Sentrix_Position,
data_overview.HybNR,
data_overview.Pool_ID
FROM tissue INNER JOIN (
( patient INNER JOIN data_overview
ON patient.Sample = data_overview.Sample)
INNER JOIN Samples ON
(data_overview.Sample_id = Samples.Sample_id) AND
(patient.Sample = Samples.Sample)
) ON
(tissue.Sample_Name = data_overview.Sample_Name) AND
(tissue.Sample_Name = patient.Sample_Name)
WHERE data_overview.Sentrix_ID= 1416198
OR data_overview.Pool_ID='GS0005701-OPA'
OR data_overview.Pool_ID='GS0005702-OPA'
OR data_overview.Pool_ID='GS0005703-OPA'
OR data_overview.Pool_ID='GS0005704-OPA'
OR data_overview.Sentrix_ID= 1280307
ORDER BY Samples.Sample;")
And the other is
SELECT Samples.Sample,
data_overview.Sample_Name,
data_overview.Sample_Group,
data_overview.NorTum,
data_overview.Sample_Plate,
data_overview.Sentrix_ID,
data_overview.Sentrix_Position,
data_overview.HybNR,
data_overview.Pool_ID
FROM tissue INNER JOIN
(
(patient INNER JOIN data_overview
ON patient.Sample = data_overview.Sample)
INNER JOIN Samples ON
(data_overview.Sample_id = Samples.Sample_id)
AND (patient.Sample = Samples.Sample)) ON
(tissue.Sample_Name = data_overview.Sample_Name)
AND (tissue.Sample_Name = patient.Sample_Name)
WHERE ((
(data_overview.Sentrix_ID)=1280307)
AND (
(data_overview.Pool_ID)="GS0005701-OPA"
OR (data_overview.Pool_ID)="GS0005702-OPA"
OR (data_overview.Pool_ID)="GS0005703-OPA"
OR (data_overview.Pool_ID)="GS0005704-OPA"))
OR (((data_overview.Sentrix_ID)=1416198))
ORDER BY data_overview.Sample;
The one in the top is working quite well but it still won't filter the sentrix_ID.
The second 1 is created with Access but when I try to run this Query in R it gave
a unexpected symbol error. So if anyone knows how to create a query that filter POOL_ID and Sentrix_id with the given parameters thanks in advance
Is it a case of making the where clause something like this:
WHERE Sentrix_ID = 1280307 AND (Pool_ID = 'VAL1' OR Pool_ID = 'VAL2' OR Pool_ID = 'VAL3')
i.e. making sure you have brackets around the "OR" components?
Maybe you meant:
...
WHERE data_overview.Sentrix_ID IN (1280307,1416198 )
AND data_overview.Pool_ID IN ("GS0005701-OPA", "GS0005702-OPA", "GS0005703-OPA" ,"GS0005704-OPA")
;