How do I link two values in a nested SQL SELECT query? - sql

I have an SQL Server table JobFiles with columns JobId and FileId. This table maps which file belongs to which job. Each job can "contain" one or more files and each file can be "contained" in one or more job. For every pair such that job M contains file N there's a row (M,N) in the table.
I start with a job id and I need to get a list of all files such that they belong to that job only. I have hard time writing a request for that. So far I've crafted the following (pseudocode):
SELECT FileId FROM JobFiles WHERE JobId=JobIdICareAbout AND NOT EXISTS
(SELECT * FROM JobFiles WHERE FileId=ThatSameFileId AND JobId<>JobIdICareAbout);
The above I believe would work but I have a problem of how to map ThatSameFileId onto the FileId returned from the outer SELECT so that the database knows that those are the same.
How do I do that? How do I tell the database that FileId in the outer SELECT must be equal to the FileId in the inner SELECT?

How about using NOT IN:
SELECT FileId FROM JobFiles WHERE JobId=JobIdICareAbout AND FileID NOT IN
(SELECT FileId FROM JobFiles WHERE JobId<>JobIdICareAbout);
And a slight variation on that:
SELECT FileId FROM JobFiles WHERE JobId=JobIdICareAbout
EXCEPT
SELECT FileId FROM JobFiles WHERE JobId<>JobIdICareAbout

I'm taking another approach here but if I understood your problem correctly, it would generate the result you need.
Gist of it goes like this
Get all FileId's from the JobId you care about
JOIN back with the JobFiles tabel
Retain only those FileId's that have no other JobId using a HAVING clause.
SQL Statement
SELECT jf1.FileId
FROM JobFiles jf1
INNER JOIN (
SELECT FileId
FROM JobFiles
WHERE JobID = JobIdICareAbout
) jf2 ON jf2.FileID = jf1.FileID
GROUP BY
jf1.FileId
HAVING COUNT(*) = 1

Another approach:
LEFT JOIN will only find rows if this file is linked to another job, checking for IS NULL removes those files:
SELECT JobFiles.FileId
FROM JobFiles
LEFT JOIN JobFiles OtherJobFiles ON ( OtherJobFiles.FileId = JobFiles.FileId
AND OtherJobFiles.JobId <> JobIdICareAbout )
WHERE JobFiles.JobId=JobIdICareAbout
AND OtherJobFiles.FileId IS NULL

It seems you have a lot of (different but) working answers/queries. Here's one more using NOT EXISTS. It's only a correction of what you tried:
SELECT jf.FileId
FROM JobFiles jf
WHERE jf.JobId = JobIdICareAbout
AND NOT EXISTS
( SELECT 1
FROM JobFiles jf2
WHERE jf2.FileId = jf.FileId
AND jf2.JobId <> JobIdICareAbout
)

Related

SQL Finding codes

I want to see all my customers who have received a document code Eg. [RF001], however I also want to see that they haven't received a number of document codes E.G [RF002, RF005, RF006, RF009].
All the document codes sit in 1 column, and the customer references are repeated.
Table
Customer_Ref | Doc_Code
CS001 | RF001
CS002 | RF003
CS001 | RF002
Code thats been tried is;
SELECT *
FROM Test_Data
WHERE Doc_Code = RF001
You can use NOT EXISTS to exclude unwanted results :
SELECT *
FROM Table1 tbl
WHERE
Doc_Code='RF001'
AND NOT EXISTS (SELECT 1
FROM Table1 unwanted
WHERE
tbl.Customer_Ref=unwanted.Customer_Ref
AND Doc_Code IN ('RF002', 'RF005', 'RF006', 'RF009'))
SELECT *
FROM Test_Data t1
WHERE t1.Doc_Code = 'RF001'
and not exists (select 1 from Test_Data t2
where t1.Customer_Ref = t2.Customer_Ref
and t2.Doc_Code in ('RF002', 'RF005', 'RF006', 'RF009')
There's several ways to accomplish this.
This is but one way using a join
SELECT Distinct A.CUSTOMER_REF
FROM TABLE A
LEFT JOIN (SELECT DISINTCT CUSTOMER_REF
FROM TABLE B
WHERE B.DOC_CODE IN ('RF002', 'RF005', 'RF006', 'RF009') B
ON A.CUSTOMER_REF = B.CUSTOMER_REF
WHERE A.DOC_CODE = 'RF001'
and B.Customer_REF is null
Another way is to use not exists (I'm sure someone else will do)
Another way is to use a not in (I'm sure someone else will do)
Another way is to use set logic and EXCEPT (Similar to a Union; but subtracts once set from another)
.
SELECT A.Customer_REF FROM table where DOC_CODE = 'RF001'
EXCEPT
SELECT A.Customer_REF FROM Table where DOC_CODE IN ('RF002', 'RF005', 'RF006', 'RF009')

SQL DB2 store query result into variable

Usind a DB2 tables:
This is what is done manually in a table
select app_id from table_app where APP_NAME='App_Temp';
gets me an ID, say it's 234
I copy than and do:
select * form table_roles where role_app_id=234;
gets me a row , which is my desired end result.
Is there a way save the result of the first one into a variable and do the second query without the manual step in between using local variables?
I know, you can query out the information with a very simple join between two tables, but I'd like to know, how it works with variables. Is there a way?
Just can just plug it in:
select *
from table_roles
where role_app_id = (select app_id from table_app where APP_NAME = 'App_Temp');
If there can be more than one match, use in instead of =.
You can also phrase this as a join:
select r.*
from table_roles r join
table_app
on r.role_app_id = a.app_id and APP_NAME = 'App_Temp';
However, this might return duplicates, if two apps have the same name. In that case, use select distinct:
select distinct r.*
from table_roles r join
table_app
on r.role_app_id = a.app_id and APP_NAME = 'App_Temp';

SELECT query to return a row from a table with all values set to Null

I need to make a query but get the value in every field empty. Gordon Linoff give me the clue to this need here:
SQL Empty query results
which is:
select t.*
from (select 1 as val
) v left outer join
table t
on 1 = 0;
This query wors perfectly on PostgreSQL but gets an error when trying to execute it in Microsoft Access, it says that 1 = 0 expression is not admitted. How could it be fixed to work on microsoft access?
Regards,
If the table has a numeric primary key column whose values are non-negative then the following query will work in Access. The primary key field is [ID].
SELECT t2.*
FROM
myTable AS t2
RIGHT JOIN
(
SELECT TOP 1 (ID * -1) AS badID
FROM myTable AS t1
) AS rowStubs
ON t2.ID = rowStubs.badID
This was tested with Access 2010.
I am offering this answer here, even though you didn't think it worked in my edit to your original question. What is the problem?
select t.*
from (select max(col) as maxval from table as t
) as v left join
table as t
on v.val < t.col;
You can use the following query, but it would still need a little "manual coding".
EDITS:
Actually, you do not need the SWITCH function. Modified query below.
Removed the reference to Description column from one line. Still, you would need to use a Text column name (such as Description) in the last line of the query.
For example, the following query would work for the Months table:
select Months.*
from Months
RIGHT OUTER JOIN
(select "" as DummyColumn from Months) Blank_Data
ON Months.Description = Blank_Data.DummyColumn; --hardcoded Description column

Alternative to NOT IN()

I have a table with 14,028 rows from November 2012. I also have a table with 13,959 rows from March 2013. I am using a simple NOT IN() clause to see who has left:
select * from nov_2012 where id not in(select id from mar_2013)
This returned 396 rows and I never thought anything of it, until I went to analyze who left. When I pulled all the ids for the lost members and put them in a temp table (##lost), 32 of them were actually still in the mar_2013 table. I can pull them up when I search for their ids using the following:
select * from mar_2013 where id in(select id from ##lost)
I can't figure out what is going on. I will mention that the id field I created is an IDENTITY column. Could that have any effect on the matching using NOT IN? Is there a better way to check for missing rows between tables? I have also tried:
select a.* from nov_2012 a left join mar_2013 b on b.id = a.id where b.id is NULL
And received the same results.
This is how I created the identity field;
create table id_lookup( dateofcusttable date ,sin int ,sex varchar(12) ,scid int identity(777000,1))
insert into id_lookup (sin, sex) select distinct sin, sex from [Client Raw].dbo.cust20130331 where sin <> 0 order by sin, sex
This is how I added the scid into the march table:
select scid, rowno as custrowno
into scid_20130331
from [Client Raw].dbo.cust20130331 cust
left join id_lookup scid
on scid.sin = cust.sin
and scid.sex = cust.sex
update scid_20130331
set scid = custrowno where scid is NULL --for members who don't have more than one id or sin information is not available
drop table Account_Part2_Current
select a.*, scid
into Account_Part2_Current
from Account_Part1_Current a
left join scid_20130331 b
on b.custrowno = a.rowno_custdmd_cust
I then group all the information by the scid
I would prefer this form (and here's why):
SELECT a.id --, other columns
FROM dbo.nov_2012 AS a
WHERE NOT EXISTS (SELECT 1 FROM dbo.mar_2013 WHERE id = a.id);
However this should still give the same results as what you've tried, so I suspect there is something about the data model that you're not telling us - for example, is mar_2013.id nullable?
this is logically equivalent to not in and is faster than not in.
where yourfield in
(select afield
from somewhere
minus
select
thesamefield
where you want to exclude the record
)
It probably isn't as fast as using where not exists, as per Aaron's answer so you should only use it if not exists does not provide the results you want.

Efficiently checking if more than one row exists in a recordset

I'm using SQL Server 2008 R2, and I'm trying to find an efficient way to test if more than 1 row exists in a table matching a condition.
The naive way to do it is a COUNT:
IF ( SELECT COUNT(*)
FROM Table
WHERE Column = <something>
) > 1 BEGIN
...
END
But this requires actually computing a COUNT, which is wasteful. I just want to test for more than 1.
The only thing I've come up with is a COUNT on a TOP 2:
IF ( SELECT COUNT(*)
FROM ( SELECT TOP 2 0 x
FROM Table
WHERE Column = <something>
) x
) > 1 BEGIN
...
END
This is clunky and requires commenting to document. Is there a more terse way?
If you have a PK in the table that you're checking for >1 row, you could nest another EXISTS clause. Not sure if this is faster, but it achieves your record result. For example, assuming a Station table with a PK named ID that can have zero-to-many Location table records with a PK named ID, Location has FK StationID, and you want to find the Stations with at least two Locations:
SELECT s.ID
FROM Station s
WHERE EXISTS (
SELECT 1
FROM Location L
WHERE L.StationID = s.ID
AND EXISTS (
SELECT 1
FROM Location L2
WHERE L2.StationID = L.StationID
AND L2.ID <> L.ID
)
)
I have the following solution to share, which may be lighter performance-wise.
I suppose that you are trying to fetch the first record and process it once you make sure that your SQL selection returns a single record. Therefore, go on and fetch it, but once you do that, try to fetch the next record right away, and if successful, you know that more than one record exists, and you can start your exception processing logic. Otherwise, you can still process your single record.