SQL Query to retrieve result without duplication - sql-server

I have table named Schedule which has fields named TeacherName and ClassTakenDate.The values in the table are as shown below:
TeacherName ClassTakenDate
Anish 2011-10-01
Anish 2011-10-01
John 2011-10-01
John 2011-10-02
I want result like this :
TeacherName NoOfDays
Anish 1
John 2
how we can do this?

SELECT TeacherName,
COUNT(DISTINCT ClassTakenDate) AS NoOfDays
FROM Schedule
GROUP BY TeacherName

SELECT TeacherName, ClassTakenDate, COUNT( * ) AS NoOfDays
FROM (
SELECT DISTINCT TeacherName, ClassTakenDate
FROM Schedule
) AS foo
GROUP BY foo.ClassTakenDate

Related

how to get multiple min values from two SQL tables?

I have two tables, a Members table and a Plan table. They are structured as follows.
member start_date Mplan Pplan version start_dt end_dt
John 20120701 johnplan johnplan 1 20120601 20130531
John 20130201 johnplan johnplan 2 20130601 20140531
John 20130901 johnplan
John 20131201 johnplan
I need to update the start_date on the Members table to be the minimum value present for that member but within the same Plan version.
Example:
20130201 would be changed to 20120701 and 20131201 would change to 20130901.
Code:
UPDATE Members
SET start_date =(
SELECT MIN(start_date) FROM Members a
LEFT JOIN Plan ON Mplan = Pplan AND
start_date BETWEEN start_dt AND end_dt
WHERE member=a.member
AND start_date BETWEEN start_dt AND end_dt
)
Unfortunately this sets every single start_date to 19900101 aka the lowest value in the entire table for that column.
First you need to get the minimum start date of each member for a specific plan. The following will provide you that.
select MIN(start_date) as min_date,a.member as member_name,a.Mplan as plan_name FROM Members a inner JOIN [plan] p ON a.Mplan = p.Pplan AND
start_date BETWEEN p.start_dt AND p.end_dt
group by a.member, a.Mplan
The result will be something like this.
min_date member_name plan_name
2012-07-01 00:00:00.000 John johnplan1
2013-09-01 00:00:00.000 John johnplan2
Use this to update each member's start date for a plan with the lowest start date of the respective plan.
update members
set start_date= tbl.min_date from
(SELECT MIN(start_date) as min_date,a.member as member_name,a.Mplan as plan_name FROM Members a
inner JOIN [plan] p ON a.Mplan = p.Pplan AND
start_date BETWEEN p.start_dt AND p.end_dt
group by a.member, a.Mplan) as tbl
where member=tbl.member_name and Mplan=tbl.plan_name
I created your 2 tables, members and plan, and tested this solution with sample data and it works. I hope it helps.
You really need to convert the dates to Datetime. You will have a greater precision, the possibility to store hours, days and minutes as well as access to date specific functions, international conversion and localization.
If your column is a Varchar(8), then it uses no less space than a Datetime column.
That said, what you are looking for is row_number().
Something like:
SELECT Member, MPlan, Start_Date, Row_Number() OVER (PARTITION BY Member, MPLan ORDER BY Start_Date) as Version
FROM Members
Could you try this ? I didn't test it.
With Member_start_dt as
(
select *, (select start_dt from Pplan where M.start_date <= start_dt AND M.start_date >= end_dt) as Pplan_date
from Members M
),
Member_by_plan as
(
select *, ROW_NUMBER () over (partition by Pplan_date order by start_date) num
from Member_start_dt
)
update M
Set M.start_date = MBP1.start_date
from Members M
inner join Member_by_plan MBP1 ON MBP1.member = M.Member AND num = 1
inner join Member_by_plan MBP2 ON MBP2.member = M.Member AND MBP2.Pplan_date = MBP1.Pplan_date AND MBP2.start_date = M.start_date

Max Value with unique values in more than one column

I feel like I'm missing something really obvious here.
Using T-SQL/SQL-Server:
I have unique values in more than one column but want to select the max version based on one particular column.
Dataset:
Example
ID | Name| Version | Code
------------------------
1 | Car | 3 | NULL
1 | Car | 2 | 1000
1 | Car | 1 | 2000
Target status: I want my query to only select the row with the highest version value. Running a MAX on the version column pulls all three because of the distinct values in the 'Code' column:
SELECT ID
,Name
,MAX(Version)
,Code
FROM Table
GROUP BY ID, Name, Code
The net result is that I get all three entries as per the data set due to the unique values in the Code column, but I only want the top row (Version 3).
Any help would be appreciated.
You need to identify the row with the highest version as 1 query and use another outer query to pull out all the fields for that row. Like so:
SELECT t.ID, t.Name, GRP.Version, t.Code
FROM (
SELECT ID
,Name
,MAX(Version) as Version
FROM Table
GROUP BY ID, Name
) GRP
INNER JOIN Table t on GRP.ID = t.ID and GRP.Name = t.Name and GRP.Version = t.Version
You can also use row_number() to do this kind of logic, for example like this:
select ID, Name, Version, Code
from (
select *, row_number() over (order by Version desc) as RN
from Table1
) X where RN = 1
Example in SQL Fiddle
add the top statment to force the return of a single row. Also add the order by notation
SELECT top 1 ID
,Name
,MAX(Version)
,Code
FROM Table
GROUP BY ID, Name, Code
order by max(version) desc

Query for item with subset of related items

I've got two tables:
Part (Table)
----
PartID
SerialNumber
CreationDate
Test (Table)
----
PartID
TestName
TestDateTime
TestResult
The tables have a one to many relationship on PartID, one part may have many Test entries.
What I'm trying to do is return a list of parts with the information of only the last test performed on that part.
Part Test
PartID SerialNumber CreationDate PartID TestName TestDateTime TestResult
-------------------------------- -------------------------------------------
1 555 12/9/2013 1 Test 1 1/1/2014 Pass
1 Test 2 2/2/2014 Fail
I would like to return the last test data with the part's information:
PartID SerialNumber CreationDate TestName TestDateTime TestResult
-----------------------------------------------------------------
1 555 12/9/2013 Test 2 2/2/2014 Fail
I can currently get the TestDateTime of the part's last test, but no other information with this query (as a subquery cannot return more than more item):
SELECT PartID, SerialNumber, CreationDate,
(SELECT TOP (1) TestDateTime
FROM Test
WHERE (PartID = Part.PartID)
ORDER BY TestDateTime DESC) AS LastDateTime
FROM Part
ORDER BY SerialNumber
Is there a different approach I can take to get the data I'm looking for?
Here is another way to do that only hits the Test table one time.
with SortedData as
(
SELECT PartID
, SerialNumber
, CreationDate
, TestDateTime
, ROW_NUMBER() over (Partition by PartID ORDER BY TestDateTime DESC) AS RowNum
FROM Part p
join Test t on t.PartID = p.PartID
)
select PartID
, SerialNumber
, CreationDate
, TestDateTime
from SortedData
where RowNum = 1
ORDER BY SerialNumber
If you are on 2012 or later you can also use FIRST_VALUE
Try using a sub query in your join and then filter based on that. Your Sub query should select the PardID and Max(TestDateTime)
Select TestSubQ.PartID, Max(TestSubQ.TestDateTime)
From Test TestSubQ
group by TestSubQ.PartID
Then just filter your main query by joining this table
Select Part.PartID, SerialNumber, CreationDate,
TestMain.PartID, TestMain.TestName, TestMain.TestDateTime, TestMain.TestResult
From Part
Left Outer Join (Select TestSubQ.PartID, Max(TestSubQ.TestDateTime)
From Test TestSubQ
group by TestSubQ.PartID) TestPartSub
On Part.PartID = TestPartSub.PartID
Left Outer Join Test TestMain
On TestPartSub.PartID = TestMain.PartID
And TestPartSub.TestDateTime = TestMain.TestDateTime
Order By SerialNumber
Note though that if your data only contains dates and not times then you may still end up with 2 entries if two tests were done on the same date. If time is included though it is highly unlikely that two exact datetimes will match for two different tests for any one part.

SQL Select Count Statement

I have two tables, one for Employees and the second for records. I want to get total entries for each employee and order the results by max total entry like:
Daniel 3
David 1
tblEmployee:
EID Name
1 Daniel
2 David
tblEntry:
ID Column1 EID
1 XX 1
2 XX 1
3 XX 2
4 XX 1
try this:
select emp.EID,emp.Name,COUNT(etr.EID)
as total_entries from Employee emp join Entry etr
on emp.EID=etr.EID
group by emp.EID,emp.Name
You must use group by
select count(*) from tblEmployee ee, tblEntry e where ee.eid = e.eid group by ee.name
There are several variations on this, and you don't say what version of SQL Server you're using, but I like doing it this way:
;
using A
as (
select EID
, RecordCount = COUNT(*)
from tblEntry
group by
EID
)
select a.EID
, e.Name
, a.RecordCount
from A
join tblEmployee e
on A.EID = e.EID
order by
RecordCount desc
I like doing it this way rather than joining and then summarizing because you only have to group on the minimum number of fields. EID in tblEntry is likely to already have an index on it, while Name in tblEmployee may not.

SQL Server Finding Duplicates

Say I have a table as follows
Employee RecNumber
Joe Bloggs 123456
Joe Bloggs 123456
Bob Bloggs 123457
Dup Bloggs 123456
And I just want to return all Rec Numbers where 2 People have had the same RecNumber which shouldn't happen.
Note that one person can have same request number multiple times I just want returned where 2 people have the same rec Number
So all I want returned is
123456
select record_number
from my_table
group by record_number
having count(distinct employee) > 1
SELECT A.RECNUMBER,COUNT(B.EMPLOYEE)
(SELECT DISTINCT RECNUMBER FROM YOURTABLE) A,
YOURTABLE B
WHERE A.RECNUMBER = B.RECNUMBER
GROUP BY A.RECNUMBER
HAVING COUNT(B.EMPLOYEE)=2;
Something like this?
SELECT RecNumber FROM Table GROUP BY RecNumber HAVING COUNT(*) > 1
SELECT RecNumber FROM [a table]
GROUP BY RecNumber HAVING COUNT(*) > 1;
Or perhaps
SELECT RecNumber FROM (SELECT RecNumber, Employee
FROM [a table]
GROUP BY RecNumber, Employee HAVING COUNT(*) > 1
) AS x;
You can write something like that, i think it's working :
use *DATABASE_NAME*
go
select *Your_Field*, Nbre=count(*Your_Field*) from *TABLE_NAME*
group by *Your_Field*
having count(*Your_Field*)>1
order by 2 desc
Enjoy

Resources