SQL JOIN limit results to rows where specific value does not exist - sql

I am joining two tables using SQL. I'm joining a table which contains charter flight information and a table which contains the crew assigned. In my results, I only want to display the rows that only have a value of "Pilot" in the the crew table and not "Copilot" or both.

SELECT * FROM TABLE_A JOIN TABLE_B ON (TABLE_A.Value = TABLE_B.Value) WHERE TABLE_A.OtherValue = 'Pilot'
This is off the top of my head, so some syntax may be off. The main point is the WHERE clause. You can specify the value that you are looking for in the column (in your case you are looking for Pilot).
EDIT: To prevent a value you can do something like WHERE TABLE.VALUE != 'Copilot' != may need to be written as <> depending on the what SQL it is.
EDIT2: My SQL-Server is throwing a hissy and not connecting, so this is also entirely off the top of my head and I think it's a bit of a hack-job, but I think it'll do the job. :)
SELECT [CHARTER].*, COUNT(*) as Tally FROM [CHARTER] JOIN [CREW] ON ([CHARTER].[CHAR_TRIP] = [CREW].[CHAR_TRIP]) WHERE [CREW].[CREW_JOB] = 'PILOT' OR [CREW].[CREW_JOB] = 'COPILOT' GROUP BY [CHARTER].* HAVING Tally = 1
This assume that all flights have a pilot, but not all flights have a co-pilot. To get the exact display you want, you might have to use it as a sub-query (to remove the Tally column).

SELECT *
FROM charter ch
JOIN crew cr ON ch.char_trip = cr.char_trip
WHERE NOT EXISTS(SELECT *
FROM crew cr2
WHERE cr2.char_trip = ch.char_trip
AND cr2.crew_job != 'PILOT')
I think that should do the trick. The join to the crew table in line 3 is optional, and only if you need results from that table. The NOT EXISTS anti-join is what evaluates all crew for a given trip and checks for any that are not pilots.

You should really help us out here with the schema for us to provide you with a decent query. I think the most important thing here is how do you determine who is a pilot and/or copilot and how do you relate each person to the flight.
I think something like this might help:
SELECT * FROM Charter C
INNER JOIN Crew ON (Charter.CHAR_TRIP = Crew.CHAR_TRIP)
WHERE Crew.Crew_Job = 'PILOT' AND (SELECT COUNT(*) FROM Charter
INNER JOIN Crew ON (Charter.CHAR_TRIP = Crew.CHAR_TRIP)
WHERE Crew.Crew_Job = 'CoPilot'
AND Charter.Chart_Trip = C.ChartTrip) = 0
Although this might not be the cleanest solution.. it should do the work.

Related

Non null value associated with least value in other column

My data is like this:
Desired output:
I have tried using following SQL:
CASE
WHEN (MINDAY_DIFF > 0) AND (MINDAY_DIFF IS NOT NULL)
THEN FIRST_VALUE(BP_MED) OVER (PARTITION BY ID ORDER BY MINDAY_DIFF ASC)
END AS DRUG
This returns NULL.
I also tried
CASE
WHEN (MINDAY_DIFF > 0)
THEN BP_MED
ELSE NULL
END AS DRUG
It returns both non-null values of BP_MED.
I also tried NVL but that didn't work either.
Since it is in Netezza. There are fewer solutions online. Please help.
The concept here is the following working inside out:
We didn't always have analytics to make things easier: So not knowing Netezza I took a more... antiquated approach. There may be better/more efficient ways; which I would look for given a place to play around with; but I think this would work in most any RDBMS as I tried to avoid any RDBMS Specific aspects unless we're dealing with pre left join supported RDBMS.
Find the Min ID and the day difference for that ID in a result set (MinAndID)
LEFT Join back to the baseSet to get all possible values specifically to get BP_Med
Then Join back to base Table to ensure we get ALL records and then populate only the BP_Med which links to the minDay_Diff. Since it's a left join only 1 record per ID should return.
UNTESTED:
SELECT A.*, DesiredDrug.BP_MED
FROM TABLE A
LEFT JOIN (SELECT ID, Fill_Date, BP_MED, MinDay_Diff
FROM TABLE BaseSet
INNER JOIN (SELECT MIN(MINDAY_DIFF) MDD, ID
FROM TABLE
WHERE ID is not null
GROUP BY ID) MinAndID
on BaseSet.ID = MinAndID.ID
and BaseSet.MinDay_Diff = MinAndID.MDD) DesiredDrug
on A.ID = DesiredDrug
and A.Fill_Date = DesiredDrug.Fill_Date
and A.BP_Med= DesiredDrug.BP_Med
and A.MinDay_Diff = DesiredDrug.MinDay_Diff

Compare 2 Tables and write RowID from Table A to Table B

I have Table A with RowID, Date, Vendor and Cost, Confirmed
I have table B with RowID, Date, Vendor and Cost, Confirmed
Table A list our purchases.
Table B list the statement data from the credit card.
I would like to compare Date, Vendor and Cost in Table A with the same columns in Table B. If there is a match with those three columns, then I would like to take the RowID value from Table A and write it to the matching row in Table B under the Confirmation column.
I am very new to SQL and I am not even sure this is a reasonable expectation.
What do you think?
Is this enough detail to provide your opinion?
Thank you for any help you can give.
Currently I am using an Outer Right Join to get all the rows that do NOT have a match. What I really need is the opposite.
It might help to know what database engine you are using...
My answers are going to relate to MS SQL Server, but much SQL Syntax is the same...
To answer your first question, I would write something like:
Update TableB Set Confirmation = TableA.RowID From TableA
Where TableA.Vendor = TableB.Vendor
And TableA.Cost = TableB.Cost
And TableA.Date = TableB.Date
I would use aliases, but I left them out to hopefully make it easier to understand.
To answer your second question, you can specify an INNER JOIN which is the opposite of an OUTER JOIN and as you mentioned, what you are looking for, as it will return ALL rows that Match and exclude the rest.
You can do this with this query
UPDATE
B
SET
Confirmation = A.RowID
FROM
TableA A
INNER JOIN TableB B
ON B.Vendor = A.Vendor
AND B.Cost = A.Cost
AND B.Date = A.Date
Basically we do an inner join to keep the intersection (the records that match) of the two tables. and update the records that coincided from table B with the id of table A

Issue with joins in a SQL query

SELECT
c.ConfigurationID AS RealflowID, c.companyname,
c.companyphone, c.ContactEmail, COUNT(k.caseid)
FROM
dbo.Configuration c
INNER JOIN
dbo.cases k ON k.SiteID = c.ConfigurationId
WHERE
EXISTS (SELECT * FROM dbo.RepairEstimates
WHERE caseid = k.caseid)
AND c.AccountStatus = 'Active'
AND c.domainid = 46
GROUP BY
c.configurationid,c.companyname, c.companyphone, c.ContactEmail
I have this query - I am using the configuration table to get the siteid of the cases in the cases table. And if the case exists in the repair estimates table pull the company details listed and get a count of how many cases are in the repair estimator table for that siteid.
I hope that is clear enough of a description.
But the issue here is the count is not correct with the data that is being pulled. Is there something I could do differently? Different join? Remove the exists add another join? I am not sure I have tried many different things.
Realized I was using the wrong table. The query was correct.

Finding difference between two tables in SQL

I have two tables with exactly same schema. One is a week old and other is current. Let new record be new_data and the old be old_data. Both have a column called opportunity_id which is the primary key, sales stages(1,2,3,4..etc) and sales_values. Now in a week a sales stage may change for an opportunity or sales values of an opportunity may change. Even a new Opportunity_id may be added. I need all the data that has changed.
I am trying INNER_JOIN but that only works when opportunity_ids match.I need newly added opportunities also.
I am using MS Access, so please provide only sql solution.
Thanks
What you're looking for is the EXISTS clause. It returns rows that match on criteria (or doesn't match). Your query would look something like this:
SELECT *
FROM new_data AS n
WHERE NOT EXISTS (SELECT *
FROM old_data AS o
WHERE n.opportunity_id = o.opportunity_id
AND n.sales_stages = o.sales_stages
AND n.sales_values = o.sales_values)
You should use LEFT OUTER JOIN instead (providing the table on the left is New_Data)
SELECT n.opportunity_id, n.sales_stage, n.sales_values, [o].sales_stage, [o].sales_values
FROM new_data AS n LEFT JOIN old_data AS o
ON n.opportunity_id = [o].opportunity_id
WHERE (((n.sales_stage)<>[o].[sales_stage]))
OR (((n.sales_values)<>[o].[sales_values]))
OR ((([o].opportunity_id) Is Null));
If you truly need ALL changes, there's one more case to consider.
What about deleted keys? Meaning keys that exist in old_data and not in new_data. To get these, use the same general approach (in my limited experience OUTER JOIN seems to perform better in Access):
SELECT [o].opportunity_id
FROM new_data AS n RIGHT JOIN old_data AS o
ON n.opportunity_id = [o].opportunity_id
WHERE ((([o].opportunity_id) Is Not Null))
AND ((([n].opportunity_id) Is Null));

Why does my left join in Access have fewer rows than the left table?

I have two tables in an MS Access 2010 database: TBLIndividuals and TblIndividualsUpdates. They have a lot of the same data, but the primary key may not be the same for a given person's record in both tables. So I'm doing a join between the two tables on names and birthdates to see which records correspond. I'm using a left join so that I also get rows for the people who are in TblIndividualsUpdates but not in TBLIndividuals. That way I know which records need to be added to TBLIndividuals to get it up to date.
SELECT TblIndividuals.PersonID AS OldID,
TblIndividualsUpdates.PersonID AS UpdateID
FROM TblIndividualsUpdates LEFT JOIN TblIndividuals
ON ( (TblIndividuals.FirstName = TblIndividualsUpdates.FirstName)
and (TblIndividuals.LastName = TblIndividualsUpdates.LastName)
AND (TblIndividuals.DateBorn = TblIndividualsUpdates.DateBorn
or (TblIndividuals.DateBorn is null
and (TblIndividuals.MidName is null and TblIndividualsUpdates.MidName is null
or TblIndividuals.MidName = TblIndividualsUpdates.MidName))));
TblIndividualsUpdates has 4149 rows, but the query returns only 4103 rows. There are about 50 new records in TblIndividualsUpdates, but only 4 rows in the query result where OldID is null.
If I export the data from Access to PostgreSQL and run the same query there, I get all 4149 rows.
Is this a bug in Access? Is there a difference between Access's left join semantics and PostgreSQL's? Is my database corrupted (Compact and Repair doesn't help)?
ON (
TblIndividuals.FirstName = TblIndividualsUpdates.FirstName
and
TblIndividuals.LastName = TblIndividualsUpdates.LastName
AND (
TblIndividuals.DateBorn = TblIndividualsUpdates.DateBorn
or
(
TblIndividuals.DateBorn is null
and
(
TblIndividuals.MidName is null
and TblIndividualsUpdates.MidName is null
or TblIndividuals.MidName = TblIndividualsUpdates.MidName
)
)
)
);
What I would do is systematically remove all the join conditions except the first two until you find the records drop off. Then you will know where your problem is.
This should never happen. Unless rows are being inserted/deleted in the meantime,
the query:
SELECT *
FROM a LEFT JOIN b
ON whatever ;
should never return less rows than:
SELECT *
FROM a ;
If it happens, it's a bug. Are you sure the queries are exactly like this (and you have't omitted some detail, like a WHERE clause)? Are you sure that the first returns 4149 rows and the second one 4103 rows? You could make another check by changing the * above to COUNT(*).
Drop any indexes from both tables which include those JOIN fields (FirstName, LastName, and DateBorn). Then see whether you get the expected
4,149 rows with this simplified query.
SELECT
i.PersonID AS OldID,
u.PersonID AS UpdateID
FROM
TblIndividualsUpdates AS u
LEFT JOIN TblIndividuals AS i
ON
(
(i.FirstName = u.FirstName)
AND (i.LastName = u.LastName)
AND (i.DateBorn = u.DateBorn)
);
For whatever it is worth, since this seems to be a deceitful bug and any additional information could help resolving it, I have had the same problem.
The query is too big to post here and I don't have the time to reduce it now to something suitable, but I can report what I found. In the below, all joins are left joins.
I was gradually refining and changing my query. It had a derived table in it (D). And the whole thing was made into a derived table (T) and then joined to a last table (L). In any case, at one point in its development, no field in T that originated in D participated in the join to L. It was then the problem occurred, the total number of rows mysteriously became less than the main table, which should be impossible. As soon as I again let a field from D participate (via T) in the join to L, the number increased to normal again.
It was as if the join condition to D was moved to a WHERE clause when no field in it was participating (via T) in the join to L. But I don't really know what the explanation is.