Link: https://blog.udemy.com/sql-not-exists/
select * from customers
where NOT EXISTS (
select customerID from orders)
I had always thought that the subquery should be written such that the subquery table (orders) should have a where clause to lookup the value from the outer table (customers).
However above example seems to be without where clause in the subquery.
For example I would have written it like this:
select * from customers c
where NOT EXISTS (
select 1 from orders o
where c.customerID=o.customerID)
So does the subquery implicitly consider where clause to be on customerID in the 1st example?
The queries do different things. The first one, returns record if specific condition is true. It's like the followings:
select * from customers
where 1 = 0
select * from customers
where 1 = 1
In such cases, the condition is not referring the data in the specified table. You can use this, for example, to return or not return rows based on specific input parameter.
In your case, I expect that the NOT EXISTS ( select customerID from orders) will always be false, as orders exists, so no data is returned.
The second query is doing what you actually want - return customers that do not have any orders. I prefer using LEFT JOINs for such queries. In AdventureWorks2012 it will look like:
select count(*)
from Production.Product
where NOT EXISTS (
select ProductID from Sales.SalesOrderDetail)
select count(*)
from Production.Product c
where NOT EXISTS (
select 1 from Sales.SalesOrderDetail o
where c.ProductID=o.ProductID)
SELECT count(*)
from Production.Product c
LEFT JOIN Sales.SalesOrderDetail o
ON c.ProductID=o.ProductID
WHERE o.ProductID IS NULL
I have SQL Server data in the below format:
In the above table, parentid and sourceid are related, like the parent-child relationship.
in first-row parentid 'A' is sourceid of the second row. User will provide input of sourceid and based on that sourceid, I need to get its related child records.
For example, if the user provides input source id as 'A1', the output should be as shown below:
I tried using self join, but I am not able to get related child records in the table.
select *
from testrecords1 t1
join testrecords1 t2 on t1.parentid = t2.sourceid
where t1.sourceid = 'A1'
This query results in only one record. Please provide corrections / suggestions to achieve the desired output.
You can use Common Table Expression (CTE) for the recursive query.
The query could be written as:
;with MyCTE
as
(
SELECT Parentid, Sourceid from testrecords1 where SourceId = #SourceId
UNION ALL
SELECT t1.Parentid, t1.Sourceid from testrecords1 t1
inner join MyCTE t2 on t1.SourceId = t2.Parentid
)
SELECT * FROM MyCTE
Where #SourceId is the parameter for filter.
I have two tables
1- Table of TestModules
TestModules
2- Table of TestModule_Results
TestModule_Results
in order to get the required information for each TestModule, I am using FULL OUTER JOIN and it works fine.
FULL OUTER JOIN result
But what is required is slightly different. The above picture shows that TestModuleID = 5 is listed twice, and the requirement is to list the 'up-to-date' results based on time 'ChangedAt'
Of course, I can do the following:
SELECT TOP 1 * FROM TestModule_Results
WHERE DeviceID = 'xxx' and TestModuleID = 'yyy'
ORDER BY ChangedAt DESC
But this solution is for a single row and I want to do it in a Stored Procedure.
Expected output should be like:
ExpectedOutput
Any advise how can I implement it in a SP?
Use a Common Table Expression and Row_Number to add a field identifying the newest results, if any, and select for just those
--NOTE: a Common Table Expression requires the previous command
--to be explicitly terminiated, prepending a ; covers that
;WITH cteTR as (
SELECT *
, ROW_NUMBER() OVER (PARTITION BY DeviceID, TestModuleID
ORDER BY ChangedAt DESC) AS ResultOrder
FROM TestModule_Results
--cteTR is now just like TestModule_Results but has an
--additional field ResultOrder that is 1 for the newest,
--2 for the second newest, etc. for every unique (DeviceID,TestModuleID) pair
)
SELECT *
FROM TestModules as M --Use INNER JOIN to get only modules with results,
--or LEFT OUTER JOIN to include modules without any results yet
INNER JOIN cteTR as R
ON M.DeviceID = R.DeviceID AND M.TestModuleID = R.TestModuleID
WHERE R.ResultOrder = 1
-- OR R.ResultOrder IS NULL --add if Left Outer Join
You say "this solution is for a single row"? Excellent. Use CROSS APPLY and change the WHERE clause from hand-input literal to the fields of the original table. APPLY operates at row level.
SELECT *
FROM TestModules t
CROSS APPLY
(
SELECT TOP 1 * FROM TestModule_Results
WHERE TestModule_Results.DeviceID = TestModules.DeviceID -- put the connecting fields here
ORDER BY ChangedAt DESC
)tr
I want sql query to get the above result. The result is the maximum Id in TableA whose s_id in TableB has Stat=true i.e. 1.
The following does not do what I want:
select i.category_id,i.image_id,i.image_original,i.image_title,i.photographer
from images i
inner join schedule s
on i.scheduleid=s.scheduleid
and s.status='live'
where image_id=(select max(image_id) from images)
Use TOP to retrieve only 1 row
Use ORDER BY to control the sorting, so you get the single row you want
SELECT TOP(1) a.id, a.[image], a.s_id, b.stat, b.[desc]
FROM TableA a
JOIN TableB b on a.s_id = b.s_id
WHERE b.stat = 1
ORDER BY A.ID DESC
An SQLFiddle showing this.
I have a CTE query filtering a table Student
Student
(
StudentId PK,
FirstName ,
LastName,
GenderId,
ExperienceId,
NationalityId,
CityId
)
Based on a lot filters (multiple cities, gender, multiple experiences (1, 2, 3), multiple nationalites), I create a CTE by using dynamic sql and joining the student table with a user defined tables (CityTable, NationalityTable,...)
After that I have to retrieve the count of student by each filter like
CityId City Count
NationalityId Nationality Count
Same thing the other filter.
Can I do something like
;With CTE(
Select
FROM Student
Inner JOIN ...
INNER JOIN ....)
SELECT CityId,City,Count(studentId)
FROm CTE
GROUP BY CityId,City
SELECT GenderId,Gender,Count
FROM CTE
GROUP BY GenderId,Gender
I want to something like what LinkedIn is doing with search(people search,job search)
http://www.linkedin.com/search/fpsearch?type=people&keywords=sales+manager&pplSearchOrigin=GLHD&pageKey=member-home
It's so fast and do the same thing.
You can not use multiple select but you can use more than one CTE like this.
WITH CTEA
AS
(
SELECT 'Coulmn1' A,'Coulmn2' B
),
CETB
AS
(
SELECT 'CoulmnX' X,'CoulmnY' Y
)
SELECT * FROM CTEA, CETB
For getting count use RowNumber and CTE some think like this.
ROW_NUMBER() OVER ( ORDER BY COLUMN NAME )AS RowNumber,
Count(1) OVER() AS TotalRecordsFound
Please let me know if you need more information on this.
Sample for your reference.
With CTE AS (
Select StudentId, S.CityId, S.GenderId
FROM Student S
Inner JOIN CITY C
ON S.CityId = C.CityId
INNER JOIN GENDER G
ON S.GenderId = G.GenderId)
,
GENDER
AS
(
SELECT GenderId
FROM CTE
GROUP BY GenderId
)
SELECT * FROM GENDER, CTE
It is not possible to get multiple result sets from a single CTE.
You can however use a table variable to cache some of the information and use it later instead of issuing the same complex query multiple times:
declare #relevantStudent table (StudentID int);
insert into #relevantStudent
select s.StudentID from Students s
join ...
where ...
-- now issue the multiple queries
select s.GenderID, count(*)
from student s
join #relevantStudent r on r.StudentID = s.StudentID
group by s.GenderID
select s.CityID, count(*)
from student s
join #relevantStudent r on r.StudentID = s.StudentID
group by s.CityID
The trick is to store only the minimum required information in the table variable.
As with any query whether this will actually improve performance vs. issuing the queries independently depends on many things (how big the table variable data set is, how complex is the query used to populate it and how complex are the subsequent joins/subselects against the table variable, etc.).
Do a UNION ALL to do multiple SELECT and concatenate the results together into one table.
;WITH CTE AS(
SELECT
FROM Student
INNER JOIN ...
INNER JOIN ....)
SELECT CityId,City,Count(studentId),NULL,NULL
FROM CTE
GROUP BY CityId,City
UNION ALL
SELECT NULL,NULL,NULL,GenderId,Gender,Count
FROM CTE
GROUP BY GenderId,Gender
Note: The NULL values above just allow the two results to have matching columns, so the results can be concatenated.
I know this is a very old question, but here's a solution I just used. I have a stored procedure that returns a PAGE of search results, and I also need it to return the total count matching the query parameters.
WITH results AS (...complicated foo here...)
SELECT results.*,
CASE
WHEN #page=0 THEN (SELECT COUNT(*) FROM results)
ELSE -1
END AS totalCount
FROM results
ORDER BY bar
OFFSET #page * #pageSize ROWS FETCH NEXT #pageSize ROWS ONLY;
With this approach, there's a small "hit" on the first results page to get the count, and for the remaining pages, I pass back "-1" to avoid the hit (I assume the number of results won't change during the user session). Even though totalCount is returned for every row of the first page of results, it's only computed once.
My CTE is doing a bunch of filtering based on stored procedure arguments, so I couldn't just move it to a view and query it twice. This approach allows avoid having to duplicate the CTE's logic just to get a count.