Postgresql Query with joins - sql

I have 6 tables that I'm trying to connect together in 1 query; however, I can't quite figure out how to write the query.
Here are my tables in bold and the columns that they contain.
pg
pgid
ipg
ipgid
roid
pgid
ug
ugid
iug
iuid
roid
ugid
ro
roid
inid
in
inid
My goal is to output the inid field given certain criteria from the pg and ug tables. I want to find all the inid entries where pg.pgid=1 and ug.ugid=2. This involves a a lot of joins and I think some select in statments but I'm not familiar enough with how to piece that all together.
Here is what I have so far...
SELECT inid
FROM in
INNER JOIN ro ON in.inid = ro.inid
INNER JOIN iug ON ro.roid = iug.roid
INNER JOIN ug ON iug.ugid = ug.ugid
INNER JOIN ipg ON ro.roid = ipg.roid
INNER JOIN pg ON ipg.pgid = pg.pgid
WHERE pg.pgid = 1
AND ug.ugid = 2

You cannot name your table in, that is a reserved word in every SQL standard and in PostgreSQL. You will get a syntax error if you try. You can still force the system to accept it if you double quote the name CREATE TABLE "in" ... but then you have to remember to double-quote it every time you use it and you will get confusing error messages. In short: don't do that.
I renamed the table tbl_in and gave it an alias in the query.
Also, inid is ambiguous as SELECT item. Either use USING as join condition (then only one column inid is in the result set) or table-qualify the column name.
Otherwise the query looks fine:
SELECT i.inid -- ambiguous without table-qualification
FROM tbl_in i -- renamed table
JOIN ro ON i.inid = ro.inid
JOIN iug ON ro.roid = iug.roid
JOIN ug ON iug.ugid = ug.ugid
JOIN ipg ON ro.roid = ipg.roid
JOIN pg ON ipg.pgid = pg.pgid
WHERE pg.pgid = 1
AND ug.ugid = 2;
If you have foreign key constraints between pg and ipg and between ug and iug, then you can simplify:
SELECT i.inid -- ambiguous without table-qualification
FROM tbl_in i -- renamed table
JOIN ro ON i.inid = ro.inid
JOIN iug ON ro.roid = iug.roid
JOIN ipg ON ro.roid = ipg.roid
WHERE ipg.pgid = 1
AND iug.ugid = 2;
... because once found in iug / ipg the values are guaranteed to be present in up / pg.

Related

Two SQL Queries With Some Overlapping Data

I'm trying to combine two different SQL queries into one table. I've tried various joins and Union but it either duplicates rows or doesn't show all of them.
The first query is
Select
HW.DisplayName,
HW.LocationDetails_0B39A057_2BE8_11B2_BBE2_1E03564AA5CA,
HW.Notes_5CFC0E2A_AB82_5830_D4BB_0596CBED1984
FROM MT_Cireson$AssetManagement$HardwareAsset HW
where HardwareAssetStatus_3019ADDF_4F3D_2C55_2024_72C22E11F4CF = '866879DF-8FB6-E521-F0E3-FEF86EE1BC92'
This gives all of my hardware assets that have the status I'm looking for.
The second query is:
SELECT
hw.DisplayName,
HW.LocationDetails_0B39A057_2BE8_11B2_BBE2_1E03564AA5CA,
HW.Notes_5CFC0E2A_AB82_5830_D4BB_0596CBED1984,
UB.UPN_7641DFF7_7A20_DC04_FC1C_B6FA8715DA02
FROM MT_Cireson$AssetManagement$HardwareAsset HW
inner join Relationship Rel on HW.BaseManagedEntityId = Rel.SourceEntityId
inner join RelationshipType RT on RT.RelationshipTypeId = Rel.RelationshipTypeId
inner join MT_Microsoft$AD$UserBase UB on UB.BaseManagedEntityId = Rel.TargetEntityId
where RT.RelationshipTypeName = 'Cireson.AssetManagement.HardwareAssetHasPrimaryUser'
and HardwareAssetStatus_3019ADDF_4F3D_2C55_2024_72C22E11F4CF = '866879DF-8FB6-E521-F0E3-FEF86EE1BC92'
This gives all of the hardware assets I'm looking for that have a primary user configured, but doesn't give the assets without a primary user. I'm not sure how to either A: combine the results just putting in NULL as a primary user for records that don't have one, or B: actually query all the assets at one time and include the primary user column.
I didn't write the second query and I'm not sure exactly how it works. I've tried doing union between the queries but that duplicates the rows because the first query already contains all the elements in the second.
Edit: The PrimaryUser comes from the MT_Microsoft$AD$UserBase table. I've tried adding another column to the first and just setting it as null like:
null as primaryUser,
How about a LEFT JOIN to include all records from HW that are not in UB:
SELECT
hw.DisplayName,
HW.LocationDetails_0B39A057_2BE8_11B2_BBE2_1E03564AA5CA,
HW.Notes_5CFC0E2A_AB82_5830_D4BB_0596CBED1984,
UB.UPN_7641DFF7_7A20_DC04_FC1C_B6FA8715DA02
FROM
MT_Cireson$AssetManagement$HardwareAsset HW
INNER JOIN
Relationship Rel
ON
HW.BaseManagedEntityId = Rel.SourceEntityId
INNER JOIN
RelationshipType RT
ON
RT.RelationshipTypeId = Rel.RelationshipTypeId
LEFT JOIN
MT_Microsoft$AD$UserBase UB
ON
UB.BaseManagedEntityId = Rel.TargetEntityId
WHERE
RT.RelationshipTypeName = 'Cireson.AssetManagement.HardwareAssetHasPrimaryUser'
AND HardwareAssetStatus_3019ADDF_4F3D_2C55_2024_72C22E11F4CF = '866879DF-8FB6-E521-F0E3-FEF86EE1BC92'
UPDATE:
If the null primary users is what you want, I would recraft the query like:
SELECT
hw.DisplayName,
HW.LocationDetails_0B39A057_2BE8_11B2_BBE2_1E03564AA5CA,
HW.Notes_5CFC0E2A_AB82_5830_D4BB_0596CBED1984,
UB.UPN_7641DFF7_7A20_DC04_FC1C_B6FA8715DA02
FROM
MT_Cireson$AssetManagement$HardwareAsset HW
LEFT JOIN
MT_Microsoft$AD$UserBase UB
ON
HW.BaseManagedEntityId = UB.SourceEntityId
INNER JOIN
RelationshipType RT
ON
RT.RelationshipTypeId = Rel.RelationshipTypeId
INNER JOIN
Relationship Rel
ON
UB.BaseManagedEntityId = Rel.TargetEntityId
WHERE
RT.RelationshipTypeName = 'Cireson.AssetManagement.HardwareAssetHasPrimaryUser'
AND HardwareAssetStatus_3019ADDF_4F3D_2C55_2024_72C22E11F4CF = '866879DF-8FB6-E521-F0E3-FEF86EE1BC92'
I LEFT JOIN'ed HW and UB tables.
As I said earlier, you'll have to tweak the joins. I would try a LEFT JOIN on all tables.
you have an extra column in your 1st query that's why you have duplicates in your union. I would suggest using CTE, there might be other better efficient solutions out there.
;WITH query1
AS
(
SELECT col1, col2
FROM table
),
query2 AS
(
SELECT col1, col2
FROM table
)
SELECT *
FROM cteTable1
UNION ALL
SELECT *
FROM cteTable2
WHERE NOT EXISTS(SELECT * FROM cteTable1 WHERE cteTable1.col1 = cteTable2.col2)

View data from one table but based on other table (SQL Server)

I want to display all information of table program but it must based on other table (which is Line), I try to use join but it will show ALL information from ALL TABLE.
Can someone help me to create the query or just tell me what should i do.
TABLE LINE
------------
LineName
TABLE PACKAGE
-------------
PackageNo
PackageName
Line
TABLE FAMILY
------------
FamilyCode
FamilyName
TestQuant
TABLE PROGRAM
-------------
FamilyName
TestType
FolderPath
TestProgram
Remark
CreateTime
And this is what i have done
SELECT * FROM Program AS D
JOIN Family AS Q ON D.FamilyName = Q.FamilyName
JOIN Process AS V ON Q.TestQuant = V.PackageNo
JOIN Line AS R ON R.LineName = V.Line
WHERE V.Line = 'LINE1'
WHAT I HAVE CHANGE
SELECT DISTINCT D.FamilyName, D.TestType, D.FolderPath, D.TestProgram, D.Remark,
D.CreateTime
FROM Program D
INNER JOIN Family Q ON D.FamilyName = Q.FamilyName
INNER JOIN Process V ON Q.TestQuant = V.PackageNo
INNER JOIN Line R ON R.LineName = V.Line
WHERE V.Line = 'LINE1'
If you need ONLY the data from Program table, try this:
SELECT D.FamilyName, D.TestType, D.FolderPath, D.TestProgram, D.Remark, D.CreateTime
FROM Program D
JOIN Family Q ON D.FamilyName = Q.FamilyName
JOIN Process V ON Q.TestQuant = V.PackageNo
JOIN Line R ON R.LineName = V.Line
WHERE V.Line = 'LINE1'
It sounds like you may need a left or right outer join. Here is an example question that has some very good explanations of JOINs in the answers, the venn diagrams really helped me understand:
SQL JOIN and different types of JOINs
An example of how you might construct a join (taken from Techonthenet)
SELECT columns
FROM table1
RIGHT [OUTER] JOIN table2
ON table1.column = table2.column;
Hope this helps, SQL JOIN can be a bit tricky to understand.

SQL select results not appearing if a value is null

I am building a complex select statement, and when one of my values (pcf_auto_key) is null it will not disipaly any values for that header entry.
select c.company_name, h.prj_number, h.description, s.status_code, h.header_notes, h.cm_udf_001, h.cm_udf_002, h.cm_udf_008, l.classification_code
from project_header h, companies c, project_status s, project_classification l
where exists
(select company_name from companies where h.cmp_auto_key = c.cmp_auto_key)
and exists
(select status_code from project_status s where s.pjs_auto_key = h.pjs_auto_key)
and exists
(select classification_code from project_classification where h.pcf_auto_key = l.pcf_auto_key)
and pjm_auto_key = 11
--and pjt_auto_key = 10
and c.cmp_auto_key = h.cmp_auto_key
and h.pjs_auto_key = s.pjs_auto_key
and l.pcf_auto_key = h.pcf_auto_key
and s.status_type = 'O'
How does my select statement look? Is this an appropriate way of pulling info from other tables?
This is an oracle database, and I am using SQL Developer.
Assuming you want to show all the data that you can find but display the classification as blank when there is no match in that table, you can use a left outer join; which is much clearer with explicit join syntax:
select c.company_name, h.prj_number, h.description, s.status_code, h.header_notes,
h.cm_udf_001, h.cm_udf_002, h.cm_udf_008, l.classification_code
from project_header h
join companies c on c.cmp_auto_key = h.cmp_auto_key
join project_status s on s.pjs_auto_key = h.pjs_auto_key
left join project_classification l on l.pcf_auto_key = h.pcf_auto_key
where pjm_auto_key = 11
and s.status_type = 'O'
I've taken out the exists conditions as they just seem to be replicating the join conditions.
If you might not have matching data in any of the other tables you can make the other inner joins into outer joins in the same way, but be aware that if you outer join to project_status you will need to move the statatus_type check into the join condition as well, or Oracle will convert that back into an inner join.
Read more about the different kinds of joins.

Complex Left Outer Joins in Oracle, converting to PostgreSQL

I have this enormous SQL statement, from an Oracle+SAS environment. I get most of it, but what is confusing me most are the Left Outer Joins/plus signs in the WHERE clause. I need to convert this to Postgres. I can handle the first part of the code, it's the joins that confuse me.
SELECT
--A bunch of columns from several tables
FROM prd_acct_cmp_grp pacg,
product_acct pa,
customer_acct ca,
(SELECT DISTINCT member_id, group_id
FROM group_members
WHERE group_id IN (33158, 27156, 35376, 36217)) gm,
prd_acct_acct_cmp pac,
pacg_usage pu,
sales_hierarchy sh,
sales_region sr
WHERE pacg.component_group_cd = 'AN'
AND pacg.component_grp_val IN (%s) --string that is added in later
AND pacg.product_account_id = pa.product_account_id
AND pa.customer_acct_id = ca.customer_acct_id
AND ca.customer_acct_id = gm.member_id(+)
AND pacg.product_account_id = pac.product_account_id
AND pacg.occurencce_number = pac.occurence_number
AND pac.prcmp_code = 'USAGE'
AND pacg.component_group_cd = pu.component_group_cd(+)
AND pacg.component_grp_val = pu.component_grp_val(+)
AND ca.primary_sales_rep = sh.sales_rep_id(+)
AND sh.region_cd = sr.sales_region_code(+)
I know how to do simple joins when converting from Oracle, however, this one has multiple instances of the same tables being compared for joins, mixed in with many conditions that don't need to be joined. So how would the joins be done? And would I need an additional WHERE clause at the end of the statement?
Thanks.
Try this:
SELECT
--A bunch of columns from several tables
FROM prd_acct_cmp_grp pacg
JOIN product_acct pa
ON pacg.product_account_id = pa.product_account_id
JOIN customer_acct ca
ON pa.customer_acct_id = ca.customer_acct_id
JOIN prd_acct_acct_cmp pac
ON pacg.product_account_id = pac.product_account_id
AND pacg.occurencce_number = pac.occurence_number
AND pac.prcmp_code = 'USAGE'
LEFT JOIN (SELECT DISTINCT member_id, group_id
FROM group_members
WHERE group_id IN (33158, 27156, 35376, 36217)) gm
ON ca.customer_acct_id = gm.member_id
LEFT JOIN sales_hierarchy sh
ON ca.primary_sales_rep = sh.sales_rep_id
LEFT JOIN sales_region sr
ON sh.region_cd = sr.sales_region_code
LEFT JOIN pacg_usage pu
ON pacg.component_group_cd = pu.component_group_cd
AND pacg.component_grp_val = pu.component_grp_val
WHERE pacg.component_group_cd = 'AN'
AND pacg.component_grp_val IN (%s) --string that is added in later

Selecting the first row out of many sql joins

Alright, so I'm putting together a path to select a revision of a particular novel:
SELECT Catalog.WbsId, Catalog.Revision, NovelRevision.Revision
FROM Catalog, BookInCatalog
INNER JOIN NovelMaster
INNER JOIN HasNovelRevision
INNER JOIN NovelRevision
ON HasNovelRevision.right = NovelRevision.obid
ON HasNovelRevision.Left=NovelMaster.obid
ON NovelMaster.obid = BookInCatalog.Right
WHERE Catalog.obid = BookInCatalog.Left;
This returns all revisions that are in the Novel Master for each Novel Master that is in the catalog.
The problem is, I only want the FIRST revision of each novel master in the catalog. How do I go about doing that? Oh, and btw: my flavor of sql is hobbled, as many others are, in that it does not support the LIMIT Function.
****UPDATE****
So using answer 1 as a guide I upgraded my query to this:
SELECT Catalog.wbsid
FROM Catalog, BookInCatalog, NovelVersion old, NovelMaster, HasNovelRevision
LEFT JOIN NovelVersion newRevs
ON old.revision < newRevs.revision AND HasNovelRevision.right = newRevs.obid
LEFT JOIN HasNovelRevision NewerHasNovelRevision
ON NewerHasNovelRevision.right = newRevs.obid
LEFT JOIN NovelMaster NewTecMst
ON NewerHasNovelRevision.left = NewTecMst.obid
WHERE Catalog.programName = 'E18' AND Catalog.obid = BookInCatalog.Left
AND BookInCatalog.right = NewTecMst.obid AND newRevs.obid = null
ORDER BY newRevs.documentname;
I get an error on the fourth line:
"old"."revision": invalid identifier
SOLUTION
Well, I had to go to another forum, but I got a working solution:
select nr1.title, nr1.revision
from novelrevision nr1
where nr1.revision in (select min(revision) from novelrevision nr2
where nr1.title = nr2.title)
So this solution uses the JOIN mentioned by the OA, along with the IN keyword to match it to a revision.
Something like this might work, it's called an exclusive left join:
....
INNER JOIN NovelRevision
ON HasNovelRevision.right = NovelRevision.obid
LEFT JOIN NovelRevision as NewerRevision
ON HasNovelRevision.right = NewerRevision.obid
AND NewerRevision.revision > NovelRevision.revision
...
WHERE NeverRevision.obid is null
The where clause filters out rows for which a newer revision exists. This effectively limits the query to the newest revisions.
In response to your comment, you could filter out only revisions that have a newer revision in the same NovelMaster. For example:
....
LEFT JOIN NovelRevision as NewerRevision
ON HasNovelRevision.right = NewerRevision.obid
AND NewerRevision.revision > NovelRevision.revision
LEFT JOIN HasNovelRevision as NewerHasNovelRevision
ON NewerHasNovelRevision.right = NewerRevision.obid
LEFT JOIN NovelMaster as NewerNovelMaster
ON NewerHasNovelRevision.left = NewerNovelMaster.obid
AND NewerNovelMaster.obid = NovelMaster.obid
....
WHERE NeverNovelMaster.obid is null
P.S. I don't think you can group JOINs and follow them with a group of ON conditions. An ON must directly follow its JOIN.
You can use CTE
Check this
WITH NovelRevesion_CTE(obid,RevisionDate)
AS
(
SELECT obid,MIN(RevisionDate) RevisionDate FROM NovelRevision Group by obid
)
SELECT Catalog.WbsId, Catalog.Revision, NovelRevision.Revision
FROM Catalog, BookInCatalog
INNER JOIN NovelMaster
INNER JOIN HasNovelRevision
INNER JOIN NovelRevesion
INNER JOIN NovelRevesion_CTE
ON HasNovelRevision.[right] = NovelRevision.obid
ON HasNovelRevision.[Left]=NovelMaster.obid
ON NovelMaster.obid = BookInCatalog.[Right]
ON NovelRevesion_CTE.obid = NovelRevesion.obid
WHERE Catalog.obid = BookInCatalog.[Left];
First it select the first revision written for each novel (assuming obid is novel foriegn key) by taking the smallest date and group them.
then add it as join in your query