Exists in where clause return incorrect result - sql

Please consider this Query:
SELECT tesd.State_Code,
tesd.City_Code,
tesd.Row_ID,
tesd.Qsno,
tesd.Total_Period,
tesd.Current_Period,
tesd.Week,
tesd.Block_No,
tesd.Family_ID,
tesd.Line_ID,
tesd.Page_ID
INTO #tmp
FROM Specification_Master tesm
INNER JOIN Specification_Details tesd
ON tesd.Master_Id = tesm.Id
WHERE tesm.[Year] = 2000
AND tesm.[Month] = 10
AND tesd.City_Code IN ('001')
I queried some data from 2 tables and insert them in #tmp .then I want to select data from 2 other tables and check one of that tables has values in #tmp tbale:
SELECT *
FROM tbl_Details D
INNER JOIN tbl_Master tem
ON D.ID_Master = tem.Id
WHERE D.Period <= 5
AND EXISTS (
SELECT Row_ID
FROM #tmp tm
WHERE tm.Current_Period > 1
AND tm.State_Code = tem.State_Code
AND tm.City_Code = tem.City_Code
AND tm.Qsno = tem.Qsno
)
AND D.[Status] > 2
when I run this query I got just one row but when I change EXISTS to NOT EXISTS I got more rows.I run this query seperatly :
SELECT Row_ID
FROM #tmp tm,tbl_Master tem
WHERE tm.Current_Period > 1
AND tm.Ostan_Code = tem.State_Code
AND tm.City_Code = tem.City_Code
AND tm.Porseshname_ID = tem.Qsno
and it returns 30 rows. Why Exists has this such behaivior ?

Exists returns a Boolean value based on the results of the subquery. It matters not if there are 1 or 30 rows returned. The number of rows you are retrieving is based on the select * statement, not the Exists clause.

Related

How to write a query to get data count with combination of codision

I have two tables named [DrugPrescriptionEdition] and [PrescriptionDoseDetail] and now, I join that two tables using the below query and taking a result set.
select * from DrugPrescription dp where id in(
SELECT distinct dpe.template
FROM [DrugPrescriptionEdition] dpe
join PrescriptionDoseDetail pdd on pdd.prescription = dpe.id
where doseEnd_endDate is NULL and doseEnd_doseEndType =1
)
but now I want to take records only contain, (1,2) combination of 'datasource' column and prescription.id should be same.
Example : like records { prescriptionID =4 and there contain ,(1,2) }. I will not consider, only 1 ,or 2 contain records.
Need some expert help to adding this conditions to my above query and modify it .
Expected result : I need to filter out , above query result using this, new condition too.
Let me assume your records are in a single table. Here is one method:
select t.*
from t
where (t.dataSource = 1 and
exists (select 1
from t t2
where t2. prescriptionid = t.prescriptionid and
t2.dataSource = 2
)
) or
(t.dataSource = 2 and
exists (select 1
from t t2
where t2.prescriptionid = t.prescriptionid and
t2.dataSource = 2
)
);
It is unclear if any other data sources are allowed. If they are not, then add:
and
not exists (select 1
from t t3
where t3.prescriptionid = t.prescriptionid and
t3.dataSource not in (1, 2)
)

SQL Server 2005 - cross apply, tvf, and update/delete

How can I make something like this
select
a.atest, a.btest, a.ctest, b.atest, b.btest
from
test.dbo.rm a(nolock)
cross apply
wat.dbo.ar(a.atest,a.btest) b
where
a.rmd = 9 and a.btest > 0
alter function ar(#atest varchar(25), #btest numeric(19,5))
returns table as
return
(
select atest, btest from test.dbo.rm (nolock)
where rmd = 1 and atest=#atest and btest=#btest
)
with delete statement or update. I don't want to make duplicates so after I choose one b.atest I want to delete the record with b.atest or set b.btest to 0. This query is working on table that contain about 5-10 million of records.. so it must be quick.
Use query without function:
select a.atest,a.btest,a.ctest,b.atest,b.btest
from test.dbo.rm a(nolock)
cross apply (
select top 1 atest, btest
from test.dbo.rm t (nolock)
where t.rmd = 1 and t.atest=a.atest and t.btest=a.btest
)b
where a.rmd = 9 and a.btest > 0
You can also use Left join instead of cross apply:
select *
from (
select a.atest,a.btest,a.ctest,b.atest,b.btest,
row_number() over ( partition by b.atest, b.btest order by b.id) as row
from test.dbo.rm a(nolock)
LEFT JOIN test.dbo.rm b ON b.rmd = 1 and b.atest=a.atest and b.btest=a.btest
where a.rmd = 9 and a.btest > 0
)z
where z.row = 1

COUNT (DISTINCT column_name) Discrepancy vs. COUNT (column_name) in SQL Server 2008?

I'm running into a problem that's driving me nuts.
When running the query below, I get a count of 233,769
SELECT COUNT(distinct Member_List_Link.UserID)
FROM Member_List_Link with (nolock)
INNER JOIN MasterMembers with (nolock)
ON Member_List_Link.UserID = MasterMembers.UserID
WHERE MasterMembers.Active = 1 And
Member_List_Link.GroupID = 5 AND
MasterMembers.ValidUsers = 1 AND
Member_List_Link.Status = 1
But if I run the same query without the distinct keyword, I get a count of 233,748
SELECT COUNT(Member_List_Link.UserID)
FROM Member_List_Link with (nolock)
INNER JOIN MasterMembers with (nolock)
ON Member_List_Link.UserID = MasterMembers.UserID
WHERE MasterMembers.Active = 1 And Member_List_Link.GroupID = 5
AND MasterMembers.ValidUsers = 1 AND Member_List_Link.Status = 1
To test, I recreated all the tables and place them into temp tables and ran the queries again:
SELECT COUNT(distinct #Temp_Member_List_Link.UserID)
FROM #Temp_Member_List_Link with (nolock)
INNER JOIN #Temp_MasterMembers with (nolock)
ON #Temp_Member_List_Link.UserID = #Temp_MasterMembers.UserID
WHERE #Temp_MasterMembers.Active = 1 And
#Temp_Member_List_Link.GroupID = 5 AND
#Temp_MasterMembers.ValidUsers = 1 AND
#Temp_Member_List_Link.Status = 1
And without the distinct keyword
SELECT COUNT(#Temp_Member_List_Link.UserID)
FROM #Temp_Member_List_Link with (nolock)
INNER JOIN #Temp_MasterMembers with (nolock)
ON #Temp_Member_List_Link.UserID = #Temp_MasterMembers.UserID
WHERE #Temp_MasterMembers.Active = 1 And
#Temp_Member_List_Link.GroupID = 5 AND
#Temp_MasterMembers.ValidUsers = 1 AND
#Temp_Member_List_Link.Status = 1
On a side note, I recreated the temp tables by simply running (select * from Member_List_Link into #temp...)
And now when I check to see the difference between COUNT(column) vs. COUNT(distinct column) with these temp tables, I don't see any!
So why is there a discrepancy with the original tables?
I'm running SQL Server 2008 (Dev Edition).
UPDATE - Including statistics profile
PhysicalOp column only for the first query (without distinct)
NULL
Compute Scalar
Stream Aggregate
Clustered Index Seek
PhysicalOp column only for the first query (with distinct)
NULL
Compute Scalar
Stream Aggregate
Parallelism
Stream Aggregate
Hash Match
Hash Match
Bitmap
Parallelism
Index Seek
Parallelism
Clustered Index Scan
Rows and Executes for the 1st query (without distinct)
1 1
0 0
1 1
1 1
Rows and Executes for the 2nd query (with distinct)
Rows Executes
1 1
0 0
1 1
16 1
16 16
233767 16
233767 16
281901 16
281901 16
281901 16
234787 16
234787 16
Adding OPTION(MAXDOP 1) to the 2nd query (with distinct)
Rows Executes
1 1
0 0
1 1
233767 1
233767 1
281901 1
548396 1
And the resulting PhysicalOp
NULL
Compute Scalar
Stream Aggregate
Hash Match
Hash Match
Index Seek
Clustered Index Scan
FROM http://msdn.microsoft.com/en-us/library/ms187373.aspx
NOLOCK Is equivalent to READUNCOMMITTED. For more information, see READUNCOMMITTED later in this topic.
READUNCOMMITED will read rows twice if they are the subject of a transation- since both the roll foward and roll back rows exist within the database when the transaction is IN process.
By default all queries are read committed which excludes uncommitted rows
When you insert into a temp table the select will give you only committed rows - I believe this covers all the symptoms you are trying to explain
I think i have got the answer to your question but tell me first is userid a primary key in your original table ?
if yes,then CTAS query to create temp table would not copy any primary key of original table ,it only copy NOT NULL constraint that is not a part of primary key..fine?
now what happened your original table had a primary key so count(distinct column_name) doesnt include tuples with null records and while you created temp tables , primary key doesnt get copied and hence the NOT NULL constraint doesnt get to the temp table!!
is that clear to you?
It's hard to reproduce this behaviour, so I'm punching in the dark here:
The WITH (NOLOCK) statement enables reading of uncommitted data. I'm guessing you've added that to not lock anything for your users? If you remove those and issue a
SET TRANSACTION ISOLATION LEVEL READ COMMITTED
Prior to executing the query, you should get more reliable results. But then, the tables may receive locks while executing the query.
If that doesn't work, my guess is that DISTINCT use an index to optimize. Check the queryplan, and rebuild indexes as necessary. Could be the source of your problem.
What result do you get with
SELECT count(*) FROM (
SELECT distinct Member_List_Link.UserID
FROM Member_List_Link with (nolock)
INNER JOIN MasterMembers with (nolock)
ON Member_List_Link.UserID = MasterMembers.UserID
WHERE MasterMembers.Active = 1 And
Member_List_Link.GroupID = 5 AND
MasterMembers.ValidUsers = 1 AND
Member_List_Link.Status = 1
) as m
AND WITH:
SELECT count(*) FROM (
SELECT distinct Member_List_Link.UserID
FROM Member_List_Link
INNER JOIN MasterMembers
ON Member_List_Link.UserID = MasterMembers.UserID
WHERE MasterMembers.Active = 1 And
Member_List_Link.GroupID = 5 AND
MasterMembers.ValidUsers = 1 AND
Member_List_Link.Status = 1
) as m
Ray, please try the following
SELECT COUNT(*)
FROM
(
SELECT Member_List_Link.UserID, ROW_NUMBER() OVER (PARTITION BY Member_List_Link.UserID ORDER BY (SELECT NULL)) N
FROM Member_List_Link with (nolock)
INNER JOIN MasterMembers with (nolock)
ON Member_List_Link.UserID = MasterMembers.UserID
WHERE MasterMembers.Active = 1 And
Member_List_Link.GroupID = 5 AND
MasterMembers.ValidUsers = 1 AND
Member_List_Link.Status = 1
) A
WHERE N = 1
when you use count with distinct column it doesn't count columns having values null.
create table #tmp(name char(4) null)
insert into #tmp values(null)
insert into #tmp values(null)
insert into #tmp values("AAA")
Query:-
1> select count(*) from #tmp
2> go
3
1> select count(distinct name) from #tmp
2> go
1
1> select distinct name from #tmp
2> go
name
NULL
AAA
but it works in derived table
1> select count(*) from ( select distinct name from #tmp) a
2> go
2
Note:- I tested it in Sybase

Fetching rows from two sql tables

I have two tables RecordMaster and Dummy
Both have columns like Mobile_Number and Insert_Date
I want a row like
1) from Dummy table I want to fetch those rows whose Mobile_Number And Insert_Date are same compared to RecordMaster.
2) from Dummy table I want to fetch those rows whose Mobile_Number And Insert_Date are different compared to RecordMaster.
After that in 1) condition I want to fetch only those rows whose Cpv_Status is not null.
(CPV_STATUS) is one column in the Dummy table..
Help me please ........
To meet your 1) and 3) needs ( optionally include the WHERE as you need).
SELECT d.*
FROM Dummy d
INNER JOIN RecordMaster r
ON r.mobile_number = d.mobile_number
AND r.insert_date = d.insert_date
WHERE d.Cpv_Status IS NOT NULL
2.
SELECT d.*
FROM Dummy d
WHERE NOT EXISTS
(SELECT 1
FROM RecordMaster r
WHERE r.mobile_number = d.mobile_number
AND r.insert_date = d.insert_date
)
To insert these:
INSERT INTO RecordMaster(mobile_number, insert_date)
SELECT d.mobile_number, insert_date
FROM Dummy d
WHERE NOT EXISTS
(SELECT 1
FROM RecordMaster r
WHERE r.mobile_number = d.mobile_number
AND r.insert_date = d.insert_date
)
The following query will give you all records in dummy that match the records in RecordMaster
SELECT a.Mobile_Number,a.Insert_Date ,a.Cpv_Status
FROM RecordMaster a, Dummy b
WHERE a.Mobile_Number = b.Mobile_Number and a.Insert_Date = b.Insert_Date
The following query will give you records in Dummy that don't have matching records in RecordMadter
SELECT a.Mobile_Number,a.Insert_Date ,a.Cpv_Status
FROM Dummy a
WHERE STR(a.Mobile_Number)+STR(a.Mobile_Number) not in
(SELECT STR(Mobile_Number)+STR(Insert_Date) FROM RecordMaster)
if you need both of these results combined in one result set, then use UNION like this
SELECT a.Mobile_Number,a.Insert_Date ,a.Cpv_Status
FROM RecordMaster a, Dummy b
WHERE a.Mobile_Number = b.Mobile_Number and a.Insert_Date = b.Insert_Date
UNION
SELECT a.Mobile_Number,a.Insert_Date ,a.Cpv_Status
FROM Dummy a
WHERE STR(a.Mobile_Number)+STR(a.Mobile_Number) not in
(SELECT STR(Mobile_Number)+STR(Insert_Date) FROM RecordMaster)
Lastly, you can apply any filter you want to the final result set like this:
select * from (
SELECT a.Mobile_Number,a.Insert_Date , a.Cpv_Status,a.Cpv_Status
FROM RecordMaster a, Dummy b
WHERE a.Mobile_Number = b.Mobile_Number and a.Insert_Date = b.Insert_Date
UNION
SELECT a.Mobile_Number,a.Insert_Date ,a.Cpv_Status
FROM Dummy a
WHERE STR(a.Mobile_Number)+STR(a.Mobile_Number) not in
(SELECT STR(Mobile_Number)+STR(Insert_Date) FROM RecordMaster)
) where Cpv_Status is not null

SQL Query to check if student1 has a course with student 2

I have one table and I need to check if two users, for whom I have the IDs (e.g. 20 and 21) share the same course, just true or false.
Table: jos_gj_users
Columns: id_user, id_group
Data Example: (20; 4)
(20; 5)
(20; 6)
(21; 6)
(21; 7)
The data above shows that user 20 and user 21 share the course 6 but how do I get this with SQL just by entering the IDs and without looping through the results with PHP?
Try a self-join:
SELECT T1.id_group
FROM jos_gj_users T1
JOIN jos_gj_users T2
ON T1.id_group = T2.id_group
WHERE T1.id_user = 20
AND T2.id_user = 21
To just get a "true or false" result you can check from the client to see if at least one row exists in the result set rather than fetching the entire results.
Alternatively you can do it in SQL by wrapping the above query in another SELECT that uses EXISTS:
SELECT CASE WHEN EXISTS
(
SELECT T1.id_group
FROM jos_gj_users T1
JOIN jos_gj_users T2
ON T1.id_group = T2.id_group
WHERE T1.id_user = 20
AND T2.id_user = 21
) THEN 1 ELSE 0 END AS result
This query returns either 0 (false) or 1 (true).
The idea is that you have to join the table to itself. In the first half you look for user 1 and in the second half you look for user 2. And of course only those rows that have the same id_group in both half are relevant:
SELECT count(*)
FROM jos_gj_users As j1, jos_gj_users As j2
WHERE j1.id_user = 20 AND j2.id_user = 21
AND j1.id_group = j2.id_group
This will always return one row with one column: The number of shared courses. If it is 0, they don't share any courses.
You could do it with a subselect:
select id_group
from jos_gj_users
where (id_user = 20)
and id_group in (select id_group from jos_gj_users where id_user = 21)
SELECT COUNT(*) > 0 FROM jos_gj_users WHERE id_user=54321 AND id_group IN ( SELECT id_group FROM jos_gj_users WHERE id_user = 1345 )
This is query that shows users from same groups.
SELECT
*
FROM
jos_gj_users T1
INNER JOIN jos_gj_users T2 ON T1.id_group = T2.id_group
Give this a try - it accepts the input parameters in the first bolded area, and returns a value of TRUE or FALSE via a CASE statement based on the values in the second bolded areas.
SELECT DISTINCT CASE WHEN
(SELECT DISTINCT COUNT(id_group) FROM jos_gj_users WHERE id_user IN (20, 21) GROUP BY id_group
HAVING COUNT(DISTINCT id_user) = 2) IS NOT NULL THEN 'TRUE'
ELSE 'FALSE'
END
FROM jos_gj_users