Join three tables and display in gridview as per condition - sql

In my Access database I am trying to display data from three tables:
PERS
COURSE
WORKED
I want all rows from PERS and some matching fields from COURSE and WORKED. KNO is the common field in all tables
eg : SELECT [KNO], [Name], [Company], [Location], [State] FROM [Pers]
If the KNo had done CCNA (Course.Qualification)
if he had Worked in Channai or Kolkatta or in Bangalore (Worked.Coyloc)
then only show
I used :
Select
Pers.KNO, Pers.Name, Pers.Company, Pers.Location, Pers.State
from Pers
left join (Course on pers.KNo=Course.KNO)
left join Worked.KNo=Per.KNO
where
Course.Qualification='CCNA'
and (Worked.Coyloc='Bangalore' or Worked.Coyloc='Channai or Worked.Coyloc='Kolkatta')
I am having trouble adding the [Worked] table to the query. When I just include [Pers] and [Course] I get the results I expect.
Select
Pers.KNO, Pers.Name, Pers.Company, Pers.Location, Pers.State
from Pers
left join Course
on pers.KNo=Course.KNO
where
Course.Qualification='CCNA'

If you are having trouble writing a query sometimes it is helpful to mock it up using the Query Designer in Access and then see what SQL it produces. For your query:
switching to SQL View reveals the following (reformatted for clarity):
SELECT Pers.KNO, Pers.Name, Pers.Company, Pers.Location, Pers.State
FROM
(
Pers
LEFT JOIN
Course
ON Pers.KNO = Course.KNO
)
LEFT JOIN
Worked
ON Pers.KNO = Worked.KNO
WHERE (((Course.Qualification)="CCNA") AND ((Worked.Coyloc)="Bangalore"))
OR (((Course.Qualification)="CCNA") AND ((Worked.Coyloc)="Channai"))
OR (((Course.Qualification)="CCNA") AND ((Worked.Coyloc)="Kolkatta"));
Note that the parentheses in the FROM clause are important. Access is a bit fussy about that.
Other notes:
As you may have noticed, the WHERE clause could be reorganized as
WHERE Course.Qualification="CCNA"
AND (Worked.Coyloc="Bangalore" OR Worked.Coyloc="Channai" OR Worked.Coyloc="Kolkatta")
Also, since you have specific WHERE conditions on columns in both the [Course] and [Worked] tables then you don't really need to use LEFT JOINs. INNER JOINs would have sufficed.

Related

SQL Server View tables not joining

I am incredibly new to SQL and am trying to create a view for a pizza store database. The sides ordered table and the sides names table have to be separate but need a view that combines them.
This is the code I have entered,
CREATE VIEW ordered_sides_view
AS
SELECT
ordered_side_id, side.side_id, side_name, number_ordered,
SUM(number_ordered * price) AS 'total_cost'
FROM
ordered_side
FULL JOIN
side ON ordered_side.side_id = side.side_id
GROUP BY
ordered_side_id, side.side_id, side_name, number_ordered;
The problem is that this is the resulting table.
Screenshot of view table:
How do I get the names to match the ordered sides?
You fail to understand what a FULL JOIN and an INNER JOIN operation does.
FULL JOIN returns at least every row from each table (plus any extra values from the ON clause).
INNER JOIN returns only matching row sets based on the ON clause.
OUTER JOIN returns every matching row set PLUS the side of the join that the OUTER JOIN is on (LEFT OUTER JOIN vs RIGHT OUTER JOIN).
In your picture, you can clearly see that there are no rows that match from the tables ordered_side and side...
That is why switching to an INNER JOIN returns zero rows...there are no matches on the COLUMNS YOU CHOSE TO USE.
Why in your SELECT operator do you have this:
SELECT ordered_side_id, side.side_id, side_name, number_ordered,
while your ON clause has this:
side ON ordered_side.side_id = side.side_id
ordered_side_id !=ordered_side.side_id
Investigate your columns and fix your JOIN clause to match the correct columns.
P.S. I like how you structure your queries. Very nice and what an
expert does! It makes reading MUCH, MUCH easier. :)
One suggestion I might add is structure your columns in the SELECT statement in its own row:
SELECT ordered_side_id
, side.side_id
, side_name
, number_ordered
, SUM(number_ordered * price) AS Total_Cost --or written [Total_Cost]/'Total_Cost'
FROM ordered_side
FULL JOIN side ON ordered_side.ordered_side_id = side.side_id
GROUP BY ordered_side_id
, side.side_id
, side_name
, number_ordered;

Nested SQL Joins in MS Access 2013

I normalized my data and have been trying to display data across multiple tables. I'm fairly new to SQL, so please bear with me.
What I'm trying to do is display tasks that haven't been assigned to a project yet, but contain data from various tables such as project title, company, etc (Using a LEFT JOIN and a WHERE clause).
The original code which works:
SELECT Tasks.ID, Projects_Tasks.ProjectID
FROM Tasks LEFT JOIN Projects_Tasks ON Projects_Tasks.TaskID = Tasks.ID
WHERE Projects_Tasks.ProjectID IS NULL;
The nested joins code (that doesn't work):
SELECT Tasks.ID, Projects.ProjectTitle, ProjectManagers.FirstName, ProjectManagers.LastName, Companies.Company
FROM ((((Tasks
LEFT JOIN Projects_Tasks ON Projects_Tasks.TaskID = Tasks.ID)
INNER JOIN Projects_Tasks ON Projects_Tasks.ID = Projects.ID)
INNER JOIN Projects ON Projects.ID = Projects_Tasks.ProjectID)
INNER JOIN ProjectManagers ON ProjectManagers.ID = Projects.ProjectManagerID)
INNER JOIN Companies ON Companies.ID = ProjectManagers.CompanyID
WHERE Projects_Tasks.ProjectID IS NULL;
I've tried numerous combinations, but I just can't get it to work. I've tried reversing the order of my nested joins (in case it executes from bottom to top) and I've tri
I don't enjoy writing SQL statements.The good thing about Access though is it can make your SQL statements for you in Queries
Using Query Builder:
Select the tables Project_Tasks & Project_Managers & all other tables
you want to display data
Select all the relevant data fields you want to display
Where you have the 'ProjectID' field, the Criteria section needs to have "Is Null" (don't put the quotation marks though)
Then, save the query, and run it. (You can probably just use that query, or otherwise strip out the SQL statement)
Good luck!

multiple sql joins not producing desired results

I'm new to sql and trying to tweak someone else's huge stored procedure to get a subset of the results. The code below is maybe 10% of the whole procedure. I added the lp.posting_date, last left join, and the where clause. Trying to get records where the posting date is between the start date and the end date. Am I doing this right? Apparently not because the results are unaffected by the change. UPDATE: I CHANGED THE LAST JOIN. The results are correct if there's only one area allocation term. If there is more than one area allocation term, the results are duplicated for each term.
SELECT Distinct
l.lease_id ,
l.property_id as property_id,
l.lease_number as LeaseNumber,
l.name as LeaseName,
lty.name as LeaseType,
lst.name as LeaseStatus,
l.possession_date as PossessionDate,
l.rent as RentCommencementDate,
l.store_open_date as StoreOpenDate,
msr.description as MeasureUnit,
l.comments as Comments ,
lat.start_date as atStartDate,
lat.end_date as atEndDate,
lat.rentable_area as Rentable,
lat.usable_area as Usable,
laat.start_date as aatStartDate,
laat.end_date as aatEndDate,
MK.Path as OrgPath,
CAST(laa.percentage as numeric(9,2)) as Percentage,
laa.rentable_area as aaRentable,
laa.usable_area as aaUsable,
laa.headcounts as Headcount,
laa.area_allocation_term_id,
lat.area_term_id,
laa.area_allocation_id,
lp.posting_date
INTO #LEASES FROM la_tbl_lease l
INNER JOIN #LEASEID on l.lease_id=#LEASEID.lease_id
INNER JOIN la_tbl_lease_term lt on lt.lease_id=l.lease_id and lt.IsDeleted=0
LEFT JOIN la_tlu_lease_type lty on lty.lease_type_id=l.lease_type_id and lty.IsDeleted=0
LEFT JOIN la_tlu_lease_status lst on lst.status_id= l.status_id
LEFT JOIN la_tbl_area_group lag on lag.lease_id=l.lease_id
LEFT JOIN fnd_tlu_unit_measure msr on msr.unit_measure_key=lag.unit_measure_key
LEFT JOIN la_tbl_area_term lat on lat.lease_id=l.lease_id and lat.isDeleted=0
LEFT JOIN la_tbl_area_allocat_term laat on laat.area_term_id=lat.area_term_id and laat.isDeleted=0
LEFT JOIN dbo.la_tbl_area_allocation laa on laa.area_allocation_term_id=laat.area_allocation_term_id and laa.isDeleted=0
LEFT JOIN vw_FND_TLU_Menu_Key MK on menu_type_id_key=2 and isActive=1 and id=laa.menu_id_key
INNER JOIN la_tbl_lease_projection lp on lp.lease_projection_id = #LEASEID.lease_projection_id
where lp.posting_date <= laat.end_date and lp.posting_date >= laat.start_date
As may have already been hinted at you should be careful when using the WHERE clause with an OUTER JOIN.
The idea of the OUTER JOIN is to optionally join that table and provide access to the columns.
The JOINS will generate your set and then the WHERE clause will run to restrict your set. If you are using a condition in the WHERE clause that says one of the columns in your outer joined table must exist / equal a value then by the nature of your query you are no longer doing a LEFT JOIN since you are only retrieving rows where that join occurs.
Shorten it and copy it out as a new query in ssms or whatever you are using for testing. Use an inner join unless you want to preserve the left side set even when there is no matching lp.lease_id. Try something like
if object_id('tempdb..#leases) is not null
drop table #leases;
select distinct
l.lease_id
,l.property_id as property_id
,lp.posting_date
into #leases
from la_tbl_lease as l
inner join la_tbl_lease_projection as lp on lp.lease_id = l.lease_id
where lp.posting_date <= laat.end_date and lp.posting_date >= laat.start_date
select * from #leases
drop table #leases
If this gets what you want then you can work from there and add the other left joins to the query (getting rid of the select * and 'drop table' if you copy it back into your proc). If it doesn't then look at your Boolean date logic or provide more detail for us. If you are new to sql and its procedural extensions, try using the object explorer to examine the properties of the columns you are querying, and try selecting the top 1000 * from the tables you are using to get a feel for what the data looks like when building queries. -Mike
You can try the BETWEEN operator as well
Where lp.posting_date BETWEEN laat.start_date AND laat.end_date
Reasoning: You can have issues wheres there is no matching values in a table. In that instance on a left join the table will populate with null. Using the 'BETWEEN' operator insures that all returns have a value that is between the range and no nulls can slip in.
As it turns out, the problem was easier to solve and it was in a different place in the stored procedure. All I had to do was add one line to one of the cursors to include area term allocations by date.

Group by in SQL Server giving wrong count

I have a query which works, goes like this:
Select
count(InsuranceOrderLine.AntallPotensiale) as potensiale,
COUNT(InsuranceOrderLine.AntallSolgt) as Solgt,
InsuranceProduct.Name,
InsuranceProductCategory.Name as Kategori
From
InsuranceOrderLine, InsuranceProduct, InsuranceProductCategory
where
InsuranceOrderLine.FKInsuranceProductId = InsuranceProduct.InsuranceProductID
and InsuranceProduct.FKInsuranceProductCategory = InsuranceProductCategory.InsuranceProductCategoryID
Group by
InsuranceProduct.name, InsuranceProductCategory.Name
This query over returns what I need, but when I try to add more table (InsuranceOrder) to be able to get the regardingUser column, then all the count values are way high.
Select
count(InsuranceOrderLine.AntallPotensiale) as Potensiale,
COUNT(InsuranceOrderLine.AntallSolgt) as Solgt,
InsuranceProduct.Name,
InsuranceProductCategory.Name as Kategori,
RegardingUser
From
InsuranceOrderLine, InsuranceProduct, InsuranceProductCategory, InsuranceSalesLead
where
InsuranceOrderLine.FKInsuranceProductId = InsuranceProduct.InsuranceProductID
and InsuranceProduct.FKInsuranceProductCategory = InsuranceProductCategory.InsuranceProductCategoryID
Group by
InsuranceProduct.name, InsuranceProductCategory.Name,RegardingUser
Thanks in advance
You're adding one more table to your FROM statement, but you don't specify any JOIN condition for that table - so your previous result set will do a FULL OUTER JOIN (cartesian product) with your new table! Of course you'll get duplication of data....
That's one of the reasons that I'm recommending never to use that old, legacy style JOIN - do not simply list a comma-separated bunch of tables in your FROM statement.
Always use the new ANSI standard JOIN syntax with INNER JOIN, LEFT OUTER JOIN and so on:
SELECT
count(iol.AntallPotensiale) as Potensiale,
COUNT(iol.AntallSolgt) as Solgt,
ip.Name,
ipc.Name as Kategori,
isl.RegardingUser
FROM
dbo.InsuranceOrderLine iol
INNER JOIN
dbo.InsuranceProduct ip ON iol.FKInsuranceProductId = ip.InsuranceProductID
INNER JOIN
dbo.InsuranceProductCategory ipc ON ip.FKInsuranceProductCategory = ipc.InsuranceProductCategoryID
INNER JOIN
dbo.InsuranceSalesLead isl ON ???????? -- JOIN condition missing here !!
When you do this, you first of all see right away that you're missing a JOIN condition here - how is this new table InsuranceSalesLead linked to any of the other tables already used in this SQL statement??
And secondly, your intent is much clearer, since the JOIN conditions linking the tables are where they belong - right with the JOIN - and don't clutter up your WHERE clauses ...
It looks like you added the table join which slightly multiplies count of rows - make sure, that you properly joining the table. And be careful with aggregate functions over several joined tables - joins very often lead to duplicates

SQL / Access - Left Join question, where do the values come from?

I have a cross tab query that looks like this:
State Building 1 2 3 4 5
NY
SC
FL
The problem I am having is that I want all of the states to show up, regardless of whether or not there is data. So, I need a Left Join. Unfortunately, when I substitute the Inner Join for Left Join in the code, nothing changes. I am just trying to figure out where the problem is coming from, and I think it may be one of the following causes:
The query doesn't know where to pull
the values from (The states are all
listed in a look up but this may
not be where it's looking)
Left Joins don't work on cross tab
queries.
Could someone please tell me what I am doing wrong?
Here's the SQL:
TRANSFORM Nz(Count(Demographics.ID))+0 AS CountOfID
SELECT Demographics.State
FROM Research
INNER JOIN ( Demographics
INNER JOIN [Status]
ON Demographics.ID=[Status].ID
)
ON (Research.ID=Demographics.ID)
AND (Research.ID=[Status].ID)
WHERE ((([Status].Building_Status)='Complete'))
GROUP BY Demographics.State,
[Status].Building_Status
PIVOT Research.Site In (1,2,3,4,5,6,7,8,9,10,11)
Ideally, I could specify the row values in the In statement above (which is currently specifying column values 1-10), but I don't think this can be done.
I didn't completely get your example, but from your comment "I want all of the states to show up, regardless of whether or not there is data", I think you want an "OUTER" join. Outer joins do just that -- they include data regardless of whether or not there is a "match". Inner joins (the default) include data only if there is a match.
Hope this helps,
John
You should change it this way:
TRANSFORM Nz(Count(Demographics.ID))+0 AS CountOfID
SELECT Demographics.State
FROM Demographics
LEFT JOIN ( Research
LEFT JOIN [Status]
ON Demographics.ID=[Status].ID
)
ON (Research.ID=Demographics.ID)
AND (Research.ID=[Status].ID)
WHERE ((([Status].Building_Status)='Complete'))
GROUP BY Demographics.State,
[Status].Building_Status
PIVOT Research.Site In (1,2,3,4,5,6,7,8,9,10,11)
If your problem is that there may be 0 rows in table Demographics with State = 'NY' (for example) but you want to see state 'NY' in the results anyway, then you need another table e.g. States that has all the states in it, and make this your driving table:
SELECT States.State
FROM States
LEFT OUTER JOIN Demographics ON Demographics.state = States.state
...
you can use a two steps solution (it is more readable)
first enclose your actual (and working) sql statment as a view
create view step1 as
TRANSFORM ....
SELECT ...
FROM ...
PIVOT ...
and then create a select like:
(you will need a state table like #Tony Andrews says)
select * -- or whatever
from state
left join step1 on state.id = step1.state
and that's all