SQL join with references to references - sql

I am still new to SQL. I have been making good progress on my project until I ran into this problem. I have tried to search the net for this kind of problem but I cannot find anything specific to this or I am not using the correct keywords in my search.
I have three tables relevant to this problem. Apparently I do not have any kind of "describe table" command to be able to copy the output. My other queries with joins are working as expected.
Table 1 - "Sites"
ID int auto-increment key, site_code short text, site_name short text, more but not relevant.
Table 2 - "Hubs"
ID int auto-increment key, HUB int (lookup from Sites.ID), more but not relevant.
Table 3 - "DialPlan"
ID int auto-increment key, site int (lookup from Sites.ID), HUB int (lookup from Hubs.HUB), more but not relevant.
When viewing the query for "DialPlan" I need to see "DialPlan.site" being replaced by "Sites.site_code" for that specific int. I need to see "DialPlan.HUB" being replaced by "Sites.site_code" for that specific int. Example of table output without joins:
DialPlan: 28, 29, 2, 203 That last number is not relevant.
Sites.ID = 29, Sites.site_name = BENN. Hubs.ID = 2, Hubs.HUB = 27, Sites.ID = 27, Sites.site_name = BRAG. So, the output I need to see when using the join is: 28, BENN, BRAG, 203. I am not getting that, I am getting: 28, BENN, BENN, 203.
My search query is:
select
Sites.site_code, Sites.site_name, Sites.site_code as Hubs.HUB,
DialPlan.OC
from
DialPlan
left join
Sites on DialPlan.site = Sites.ID
left join
Hubs on DialPlan.HUB = Hubs.ID
left join
Hubs on Hubs.HUB = Sites.ID;
I have tried to change field 3 using "AS" and even tried "=" and several other things. If I try to put field 3 as "Sites.site_code" then the output is the same as the first "Sites.site_code" lookup. I am not sure how to proceed. I have tried so many things now that I am not even sure exactly what I have tried. I saw one thread where there were multiple dots per column and I have no idea what that is used for. Does anyone have any ideas?

OK, I have found the answer and it is called an inner query. Actually there are two inner queries. I am posting this so that others may benefit from this. The problem with referencing the first table from two fields that are on the same table is that SQL cannot determine that the second call means a new search. So, you must perform an inner query to resolve this. Here is the code. As an Access admin I have always been able to get this kind result easy but I am behind the power curve for SQL. Here is the working code sample.
SELECT Sites.site_code, Sites.site_name,
( SELECT site_code FROM Sites WHERE ID =
( SELECT HUB FROM Hubs WHERE DialPlan.HUB = Hubs.ID )
),
DialPlan.OC
FROM DialPlan
LEFT JOIN Sites
ON DialPlan.site = Sites.ID;
The output is what I was looking for, "BENN Benning BRAG 203". I hope this helps someone.

When you use the AS clause you are just giving that column a title for your table. It will not fill in the data from your alias in place of the data you are aliasing.
If you want to list the data for Hubs.hub you should SELECT Hubs.hub and then give it the title you want using AS mytitle.
Also you dint need that last join as your tables are already joined.
Also, the describe command is DESC and it should work... DESC sites
select
Sites.site_code, Sites.site_name, Hubs.HUB as Site, DialPlan.OC
from
DialPlan
left join
Sites on DialPlan.site = Sites.ID
left join
Hubs on DialPlan.HUB = Hubs.ID

Related

Access SQL Lookup - Dropdown Columns

I have looked for a similar issue with no luck. Maybe I don't know the right term to search for.
This seems so simple, but I just can't get it after spending many hours trying different approaches.
I have a dropdown to select contracts which shows some ids for related fields. How can I get those IDs to show the value of another column.
SELECT tbl_contracts.ID, tbl_contracts.contract_name, tbl_contracts.firm_id, tbl_contracts.agency_id
FROM tbl_contracts;
image of dropdown
I would like the IDs shown for agency_id and firm_id to list the company_name from their respective table "tbl_firm_agencies" where the tbl_contracts looks them up from. I've tried INNER JOINS but when I do, I can only line items to show when both agency AND firm exist, so my dropdown get cut off quite a bit.
Simply LEFT JOIN to those lookup tables as opposed to INNER JOIN. Adjust table and field names to actual ones in query below. Also, the parentheses are required in MS Access SQL.
SELECT c.ID, c.contract_name, f.firm_name, a.agency_name
FROM (tbl_contracts c
LEFT JOIN tbl_firms f
ON c.firm_id = f.firm_name)
LEFT JOIN tbl_agencies a
ON c.agency_id = a.agency_name;

How to use joins to cross check data from multiple tables

I got a few tables which I need to query to crosscheck information.
All tables are in the same database.
First table is named Confirmedsitesv2 and contains a column named sites.
Sedond table is named Standardwithmail and contains three columns. sites, username and mail.
Third table named CDDump contains alot of columns but there is only three I am intrested in. Uid, employeenddate and company.
I need to query so I get site, username and mail based on the following criteria.
Site from standardwithmail matches site in confirmedsitesv2, username from standardwithmail matches uid in CDDUmp, while the employmentenddate = 0 and company is not like %test%. Mail should not be matched with anything as it only occurs in standardwithmail but will show for all the hits from the query.
So I tryed to get my head around this with left joins for nearly two hours.
Anyone experienced who can who can explain how I should use join in this situation? I done outer joins before for totaly different case and that worked easy and fine, but can't get my head around this even after alot of time on google.
If needed I can create some fake tables and upload pictures as I can't show the real data here.
Please try this:
SELECT cfrsites.sites standard.username,
standard.mail
FROM Confirmedsitesv2 cfrsites,
Standardwithmail standard,
CDDump cd
where cfrsites.sites = standard.site
and standard.username = cd.Uid
If you can edit your post, add the Table structure and add some insert statements that will be helpful
So why mail did not work was because it's in the the big table I only used for other information, I renamed that column in standardwithmail and I ran:
select site, username, mailaddress
from Standardwithmail
left join CDDump on CDDump.uid = dbo.Standardwithmail.Username where Site in (select Site from Confirmedsitesv2) and employmentEnd like '0' and companyName not like '%test%'
order by Site;
Try out the following query. You don't need outer join or left join, but just inner joins since you only want matching records.
SELECT swm.username,
swm.mail
FROM standardwithmail swm
INNER JOIN confirmedsitesv2 csv2
ON swm.sites = csv2.sites
INNER JOIN cddump cdd
ON swm.username = cdd.uid
WHERE cdd.employmentenddate = 0
AND
cdd.company NOT LIKE '‰test‰'

New to SQL and need some advice with queries

I have recently started learning SQL but can't seem to get my head around creating SQL statements that form relevant results from multiple tables/relations.
Given the following schema:
Account(accNumber, balance, type)
Branch(BSB, phone, streetAddress, town)
registered(accNumber*, BSB*)
I am trying to formulate some outputs:
List all the accNumber registered with a specific BSB (123) and show its listed town (Sydney).
I have tried the following statement for the first query:
SELECT accNumber, BSB, town
FROM ACCOUNT, BRANCH
WHERE BSB = 123;
However, I get every account listed even if they don't belong to the BSB, so I tried:
SELECT accNumber, BSB, town
FROM ACCOUNT, BRANCH
WHERE BSB = 123
AND Town = 'Sydney'
AND account.accNumber=registered.accNumber
AND branch.bsb=registered.bsb;
This time I get column ambiguously defined because they have the same name in the "registered" table.
I've tried making alias in the select statment i.e. accNumber AS ACCOUNT_NUMBER etc, but still getting ambiguously defined errors.
I tried just listing what was in the registered table but then I do not get the town name, just the accNumber and the BSB passed in as a foreign key.
I can't seem to understand how to pull data from other tables and display them correctly and would greatly appreciate any advice!
This might help you start.
SELECT a.ccNumber, b.BSB, c.town
FROM ACCOUNT as a
inner join registered as b on b.accNumber=a.accNumber
inner join BRANCH as c on c.bsb = b.bsb
WHERE b.BSB = 123
AND c.Town = 'Sydney'
So this sounds like a generic SQL question. For your query here is what you're looking at:
select a.account_number
from account a, brance b, registered r
where a.account_number = r.account_number and
a.bsb = b.bsb and
b.bsb = 123;
This will get you all account numbers from the account table that are in BSB 123. When you have multiple tables that have the same column, you need to tell Oracle (and any database for that matter) which "account_number" column you're referring to (as otherwise it's ambiguous as there are multiple tables that contain the column account_number).
SQL is about tables and joins. You sometimes have to join several tables to get what you need, as above. If you don't join tables, as you did originally, you'll get a "cross product", which is not what you want.
I know this is very "light", but hopefully from the above answer to your question, you'll get some idea of how to do this.
I'd be happy to help you more if you have questions. Everyone is new to SQL at some point. Don't feel bad about that. It takes practice and then it becomes much easier.
-Jim

Find the number of certifications held by people, grouped by planet.

This is part of my SQL homework and I can't wrap my head around it. It should have two colums, name and CertCount. Where name = planet name. and CertCount = total number of certificates all people with that homeworld have.
These are the tables i'm working with: http://pastebin.com/kNRNGQFv
This is my query so far:
SELECT bsg_people.homeworld, (SUM(cid)
AS 'CertCount'
FROM bsg_people
INNER JOIN bsg_cert_people ON id=cid)
GROUP BY bsg_people.homeworld;
I just can't seem to figure this out because there is no value to count the number of certificates each person has. I appreciate any help.
Use a simple count(*), without the subquery and join to the right column - your pastebin shows that the foreign key to person is on pid (not cid):
CONSTRAINT `bsg_cert_people_ibfk_2` FOREIGN KEY (`pid`) REFERENCES `bsg_people` (`id`)
Also, join to the planets tables to get the name of the planet in your output.
Try this:
select bsg_planets.name homeworld, count(*) CertCount
from bsg_planets
join bsg_people on bsg_planets.id = bsg_people.homeworld
join bsg_cert_people on id = pid
group by bsg_planets.name
Also, you had a syntax error: You quoted the alias "CertCount" like this: 'CertCount', but that's a string literal. You need an alias, without quotes, like this CertCount.
Rather than answer your question directly (which would sort of defeat the purpose of the homework which is for you to learn), I'll try to point you in the right direction :)
How are you joining bsg_cert_people onto bsg_people? Look at which fields are referring to people and which are referring to certifications, and make sure that you're using them the correct way. While not essential in this case, using table aliases (instead of just "id=cid") and neatening up the query a bit can really help with getting a better mental picture of what the joins and such are doing.

Query to get all revisions of an object graph

I'm implementing an audit log on a database, so everything has a CreatedAt and a RemovedAt column. Now I want to be able to list all revisions of an object graph but the best way I can think of for this is to use unions. I need to get every unique CreatedAt and RemovedAt id.
If I'm getting a list of countries with provinces the union looks like this:
SELECT c.CreatedAt AS RevisionId from Countries as c where localId=#Country
UNION
SELECT p.CreatedAt AS RevisionId from Provinces as p
INNER JOIN Countries as c ON p.CountryId=c.LocalId AND c.LocalId = #Country
UNION
SELECT c.RemovedAt AS RevisionId from Countries as c where localId=#Country
UNION
SELECT p.RemovedAt AS RevisionId from Provinces as p
INNER JOIN Countries as c ON p.CountryId=c.LocalId AND c.LocalId = #Country
For more complicated queries this could get quite complicated and possibly perform very poorly so I wanted to see if anyone could think of a better approach. This is in MSSQL Server.
I need them all in a single list because this is being used in a from clause and the real data comes from joining on this.
You have most likely already implemented your solution, but to address a few issues; I would suggest considering Aleris's solution, or some derivative thereof.
In your tables, you have a "removed at" field -- well, if that field were active (populated), technically the data shouldn't be there -- or perhaps your implementation has it flagged for deletion, which will break the logging once it is removed.
What happens when you have multiple updates during a reporting period -- the previous log entries would be overwritten.
Having a separate log allows for archival of the log information and allows you to set a different log analysis cycle from your update/edit cycles.
Add whatever "linking" fields required to enable you to get back to your original source data OR make the descriptions sufficiently verbose.
The fields contained in your log are up to you but Aleris's solution is direct. I may create an action table and change the field type from varchar to int, as a link into the action table -- forcing the developers to some standardized actions.
Hope it helps.
An alternative would be to create an audit log that might look like this:
AuditLog table
EntityName varchar(2000),
Action varchar(255),
EntityId int,
OccuranceDate datetime
where EntityName is the name of the table (eg: Contries, Provinces), the Action is the audit action (eg: Created, Removed etc) and the EntityId is the primary key of the modified row in the original table.
The table would need to be kept synchronized on each action performed to the tables. There are a couple of ways to do this:
1) Make triggers on each table that will add rows to AuditTable
2) From your application add rows in AuditTable each time a change is made to the repectivetables
Using this solution is very simple to get a list of logs in audit.
If you need to get columns from original table is also possible using joins like this:
select *
from
Contries C
join AuditLog L on C.Id = L.EntityId and EntityName = 'Contries'
You could probably do it with a cross join and coalesce, but the union is probably still better from a performance standpoint. You can try testing each though.
SELECT
COALESCE(C.CreatedAt, P.CreatedAt)
FROM
dbo.Countries C
FULL OUTER JOIN dbo.Provinces P ON
1 = 0
WHERE
C.LocalID = #Country OR
P.LocalID = #Country