How to get the first and last row of data per user - c#

I'm trying to write a query to select only the first and last record for each user.
Basically I want to:
SELECT * FROM EmpData WHERE ClockNo is DISTINCT AND only the first and last record
is displayed like in the picture. N.B it's color-coded per user
Database:
CREATE TABLE [dbo].[EmpData](
[ClockNo] [nvarchar](50) NULL,
[FirstName] [nvarchar](50) NULL,
[LastName] [nvarchar](50) NULL,
[Department] [nvarchar](50) NULL,
[ClockPoint] [nvarchar](50) NULL,
[Date] [nvarchar](50) NULL,
[Time] [nvarchar](50) NULL
) ON [PRIMARY]

There are multiple approaches to doing this. But having the date/time values are in two columns makes this a hard problem. So, most methods involve date manipulations -- which can be quite database dependent.
Here is a method that requires no date/time manipulations. And, it should perform pretty well on most databases with the appropriate indexes:
select t.*
from t
where not exists (select 1
from t t2
where t2.clockno = t.clockno and
(t2.date > t.date or
t2.date = t.date and t2.time > t.time
)
) or
not exists (select 1
from t t2
where t2.clockno = t.clockno and
(t2.date < t.date or
t2.date = t.date and t2.time < t.time
)
) ;
If you want the data per day, then I would go for:
select t.*
from t join
(select clockno, date, min(time) as mint, max(time) as maxt
from t
group by clockno, date
) tt
on tt.clockno = t.clockno and tt.date = t.date and
t.time in (tt.mint, tt.maxt);

Related

How to get the difference between time on same table but on different lines

I would like to know how to get the difference between time if the data is in the same table but on two separate lines. For example, below I have a screenshot of the data, every employee have two records, the first clock point and the last clock point. I want the difference between those times and save it into a new table. How do I do that?
Table structure:
CREATE TABLE [dbo].[RefinedData](
[ClockNo] [nvarchar](50) NULL,
[FirstName] [nvarchar](50) NULL,
[LastName] [nvarchar](50) NULL,
[Department] [nvarchar](50) NULL,
[ClockPoint] [nvarchar](50) NULL,
[Date] [nvarchar](50) NULL,
[Time] [int] NULL
) ON [PRIMARY]
Layout of Data:
So in this case I want the time difference of the user Gerard saved in a new table but only one record per user.
It is apparent from your sample data , you have 2 rows of data per user.
row_number will work for you. Subtracting rn2-rn1 will return required output
with cte as
(select [ClockNo] ,
[FirstName] ,
[LastName] ,
[Department] ,
[ClockPoint] ,
[Date] ,
time,
ROW_NUMBER() over partition by clockno,firstname order by date,time) rn
from mytable
)
select c.[ClockNo] ,
c.[FirstName] ,
c.[LastName] ,
c.[Department] ,
c.[ClockPoint] ,
c.[Date] ,
c1.time -c.time
from cte c inner join (select * from cte where rn= 2) c1
on c.rn = c1.rn-1 and c.firstname = c.firstname and c.clockno = c1.cloclno
where c.rn = 1
You could do the following:
var differences =
refinedData.GroupBy(d => d.ClockNo)
.Select( g => g.OrderBy(d => d.Time))
.Select( g => new {
ClockNo = g.ClockNo,
Difference = g.Last() - g.First() });
try this-
select Firstname,cast(max(Time)-min(Time) as time) as 'time difference'
into #temptable
from RefinedData
where FirstName like 'Gerard'
and Date like '20180301'
group by Firstname
Here something you can start with:
select *, datediff(hour, LAG([Datetime]) over (partition by FirstName, LastName order by [Datetime]), [Datetime]) [Difference_in_hours]
from (
select FirstName,
LastName,
ClockPoint,
--get correctly formatted date column
cast(stuff(STUFF([DATE], len([DATE]) - 3, 0, '-'), len([DATE]), 0, '-') + ' ' + stuff(STUFF([time], len([time]) - 3, 0, ':'), len([time]), 0, ':') as datetime) [Datetime]
from [RefinedData]
) a where
ClockPoint like '% out %' or
ClockPoint like '% in %' or
ClockPoint like '% out' or
ClockPoint like '% in' or
ClockPoint like 'out %' or
ClockPoint like 'in %'

How to get data from table using sub query in sql server 2008?

I am trying to get data from tables using sub query, but i got this error :
Base table : [tblPriscription]
[Priscriptionid] [bigint] IDENTITY(1,1) NOT NULL,
[patientId] [bigint] NULL,
[doctorId] [bigint] NULL,
[BillNo] AS ([Priscriptionid]+(100)),
[BillDate] [datetime] NULL,
[BillType] [nvarchar](50) NULL,
[PaymentBy] [nvarchar](50) NULL,
[DocumentType] [nvarchar](50) NULL,
[DocumentName] [nvarchar](50) NULL,
[bitIsActive] [bit] NULL,
[dateCreated] [date] NULL,
[bitIsDelete] [bit] NULL,
[bitisSave] [bit] NULL,
[TotalAmount] [decimal](18, 2) NULL,
A table from which i want to fetch data:
dbo.tblPriscriptionDetail
[PriscriptionDtlid] [bigint] IDENTITY(1,1) NOT NULL,
[Priscriptionid] [bigint] NULL,
[drugId] [bigint] NULL,
[Rxno] [bigint] NULL,
[sigId] [bigint] NULL,
[Selling] [decimal](18, 2) NULL,
[Qty] [int] NULL,
[RefillQty] [int] NULL,
[RefillNo] [int] NULL,
[Days] [int] NULL,
[Amount] [decimal](18, 2) NULL,
[bitIsActive] [bit] NULL,
[dateCreated] [datetime] NULL,
[bitIsDelete] [bit] NULL,
[PurchaseDtlid] [bigint] NULL,
[bitIsSave] [bit] NULL,
[BillType] [nvarchar](50) NULL,
[PaymentBy] [nvarchar](50) NULL,
[patientId] [bigint] NULL,
[id] [bigint] NULL,
Qyery:
SELECT *,
(SELECT insuranceName
FROM tblinsurance
WHERE insuranceid = (SELECT insuranceid
FROM tblpatient
WHERE PatientId = tblPriscription.PatientId)) AS insuranceName,
(SELECT drfirstname + ' ' + drlastname
FROM tbldoctor
WHERE doctorid = tblPriscription.doctorid) AS doctorname,
(SELECT patFirstName + ' ' + patLastName
FROM tblPatient
WHERE patientid = tblPriscription.patientid) AS patname,
(SELECT policyno
FROM tblPatient
WHERE patientid = tblPriscription.patientid) AS policyno,
(SELECT insuranceplanname
FROM tblInsurancePlan
WHERE insuranceplanid = (SELECT insuranceplanid
FROM tblpatient
WHERE PatientId = tblPriscription.PatientId)) AS insurancePlanName,
(SELECT drugname
FROM tblDrugMaster
WHERE drugid = (SELECT drugid
FROM tblPriscriptionDetail
WHERE priscriptionid = tblPriscriptionDetail.priscriptionid)) AS drugname,
(SELECT qty
FROM tblPriscriptionDetail
WHERE priscriptionid = tblPriscriptionDetail.priscriptionid) AS qty,
(SELECT Selling
FROM tblPriscriptionDetail
WHERE priscriptionid = tblPriscriptionDetail.priscriptionid) AS selling
FROM tblPriscription
i am trying to fetch data from tblPriscriptionDetail drugname,qty and Selling suggest me, how to do that
You simply need join not messy sub query.
SELECT tp.*, tpd.qty, tpd.Selling, ti.insuranceName
FROM tblPriscription tp inner join tblPriscriptionDetail tpd ON tpd.Priscriptionid = tp.Priscriptionid
inner join tblinsurance ti ON ti.insuranceid = tp.PatientId
inner join your other tables
JOIN is the way to go, but beware of INNER JOINs unless you are sure there is always a matching record in each case - if not, then use LEFT JOINs. If you are sure INNER JOINs won't lose rows, then try this
SELECT Selling, qty, drugname, insuranceplanname, policyno, patFirstName + ' ' + patLastName AS patname, drfirstname + ' ' + drlastname AS doctorname, insuranceName
FROM tblPrescription P
INNER JOIN tblPrescriptionDetail PD ON PD.PrescriptionID = P.PrescriptionID
INNER JOIN tblDrugMaster DM ON DM.PrescriptionID = PD.PrescriptionID
INNER JOIN tblPatient PP ON PP.PatientID = P.PatientID
INNER JOIN tblInsurancePlan IP ON IP.InsuranceplanID = P.InsuranceplanID
INNER JOIN tblDoctor D ON D.DoctorID = P.DoctorID
INNER JOIN tblInsurance I ON I.InsuranceID = P.InsuranceID
I have tried to introduce some consistency in capitalisation, and have included all the fields you were extracting in your original (rather than just the ones you say you want). I'm curious that you have both tblInsurance and tblInsurancePlan.

sql query to count data entry of each hour

I want to display the count of data entry of the present day during each hour(1 hour time interval) for a particular line and finally the cumulative of all the hours.
Table details:
CREATE TABLE [dbo].[ProductTable] (
[Id] INT IDENTITY (1, 1) NOT NULL,
[ProductID] INT NOT NULL,
[EmployeeID] INT NOT NULL,
[Operation] VARCHAR (50) NOT NULL,
[Section] NCHAR (10) NOT NULL,
[Line] INT NOT NULL,
[Date] DATETIME DEFAULT (getdate()) NULL,
PRIMARY KEY CLUSTERED ([Id] ASC),
);
I am using Microsoft Visual Studio SQL server
I have written so much but don't know to generalise for every hour
SELECT COUNT(Id) AS Expr1
FROM ProductTable
WHERE (Line = 2)
AND (CONVERT(VARCHAR(10), Date, 105) = CONVERT(VARCHAR(10), GETDATE(), 105))
AND (DATEPART(hour, GETDATE()) BETWEEN 9 AND 10)`
ProductTable data
Error on using "case"
it sounds like you want to group by the hour of the day
SELECT DATEPART(hour, date) as TimeOfDay, COUNT(Id) AS Entries
FROM ProductTable
WHERE (Line = 2) AND cast ([date] as date) =cast (getdate() as date)
GROUP BY DATEPART(hour, date)
To get the cumulative of all hours of the day, use grouping sets
SELECT ISNULL(cast(DATEPART(hour,[date]) as varchar(5)),'Total') as TimeOfDay, COUNT(Id) AS Entries
FROM ProductTable
WHERE (Line = 2) AND cast ([date] as date) =cast (getdate() as date)
GROUP BY GROUPING SETS (DATEPART(hour, [date]) , ())
ORDER BY ISNULL(cast(DATEPART(hour, [date]) as varchar(5)),'Total')
simply use group by clause
SELECT COUNT(Id) AS Expr1
FROM ProductTable
where (Line = 2) AND (CONVERT(Date,[Date])) = CONVERT(DATE,GETDATE())
GROUP BY DATEPART(HOUR, Date)

SQL Join And Filter By User - Multiple Joins

I'm having an issue with SQL and I can't find out a solution. It seems to be simple.
I've four tables as follow : Task, User, Building and BuildingUser.
Task - Each user can open a task which is related to a Building
User - Stores users
Building - Stores buildings
BuildingUser - Represents a relation between User and Building. It shows which user can "see" a Building. N->N
My case:
Table Task
CREATE TABLE [dbo].[TASK]
(
[ID] [INT] IDENTITY(1, 1) NOT NULL,
[ID_USER] [INT] NOT NULL,
[ID_BUILDING] [INT] NOT NULL
)
Table Building
CREATE TABLE [dbo].[BUILDING]
(
[ID] [INT] IDENTITY(1, 1) NOT NULL,
[NAME] [VARCHAR](50) NOT NULL
)
Table User
CREATE TABLE [dbo].[USER]
(
[ID] [INT] IDENTITY(1, 1) NOT NULL,
[NAME] [VARCHAR](50) NOT NULL
)
Table BuildingUser
CREATE TABLE [dbo].[BUILDINGUSER]
(
[ID] [INT] IDENTITY(1, 1) NOT NULL,
[ID_BUILDING] [INT] NOT NULL,
[ID_USER] [INT] NOT NULL
)
Sample Data
Task
ID|ID_USER|ID_BUILDING
1 |1 |1
2 |1 |2
User
ID|Name
1 |Carlos
2 |Joao
3 |Maria
Building
ID|Name
1 |Rochavera
2 |San George
BuildingUser
ID_USER|ID_BUILDING
2 |1
3 |2
So, I want to transfer two task at the same time to as many users as possible. However, these users have to see all buildings of Tasks I've selected. For example, If I've selected Task.ID 1 and 2 The query must return "nothing" because I don't have a user who sees both buildings. But If I've selected just one task, like ID 1, I'd be able to transfer to User ID 2.
I've this query, but it's wrong. It was just a try.
SELECT DISTINCT [USER].ID,
[USER].NAME
FROM TASK
INNER JOIN BUILDINGUSER
ON BUILDINGUSER.ID_BUILDING = TASK.ID_BUILDING
INNER JOIN [USER]
ON [USER].ID = BUILDINGUSER.ID_USER
WHERE TASK.ID IN ( 1, 2 )
EDIT
I followed instructions below and got it working.
SELECT u.ID,
u.NAME
FROM TASK t
JOIN BUILDINGUSER bu
ON bu.ID_BUILDING = t.ID_BUILDING
JOIN [USER] u
ON u.ID = bu.ID_USER
WHERE t.ID IN ( 1, 2 )
AND u.ID != t.ID_USER
GROUP BY u.ID,
u.NAME
HAVING Count(bu.ID_BUILDING) = (SELECT Count(*)
FROM TASK t2
WHERE t2.ID IN ( 1, 2 ))
This is a "set-within-sets" query. You are looking for a all members of a group (the tasks) within a set.
I advocate solving this by using aggregation and putting the logic in the having clause:
select u.id, u.name
from Task t join
BuildingUser bu
ON bu.ID_BUILDING = t.ID_BUILDING join
[User] u
ON u.ID = bu.ID_USER
group by u.id, u.name
having sum(case when t.id = 1 then 1 else 0 end) > 0 and -- Any rows with taskid = 1 ?
sum(case when t.id = 2 then 1 else 0 end) > 0; -- Any rows with taskid = 2 ?
The advantage of this approach is that it is easy to generalize. Say you wanted tasks 1 and 2 but not 3. The having clause changes to:
having sum(case when t.id = 1 then 1 else 0 end) > 0 and
sum(case when t.id = 2 then 1 else 0 end) > 0 and
sum(case when t.id = 3 then 1 else 0 end) = 0;

Many-To-Many Query with Linq-To-NHibernate

Ok guys (and gals), this one has been driving me nuts all night and I'm turning to your collective wisdom for help.
I'm using Fluent Nhibernate and Linq-To-NHibernate as my data access story and I have the following simplified DB structure:
CREATE TABLE [dbo].[Classes](
[Id] [bigint] IDENTITY(1,1) NOT NULL,
[Name] [nvarchar](100) NOT NULL,
[StartDate] [datetime2](7) NOT NULL,
[EndDate] [datetime2](7) NOT NULL,
CONSTRAINT [PK_Classes] PRIMARY KEY CLUSTERED
(
[Id] ASC
)
CREATE TABLE [dbo].[Sections](
[Id] [bigint] IDENTITY(1,1) NOT NULL,
[ClassId] [bigint] NOT NULL,
[InternalCode] [varchar](10) NOT NULL,
CONSTRAINT [PK_Sections] PRIMARY KEY CLUSTERED
(
[Id] ASC
)
CREATE TABLE [dbo].[SectionStudents](
[SectionId] [bigint] NOT NULL,
[UserId] [uniqueidentifier] NOT NULL,
CONSTRAINT [PK_SectionStudents] PRIMARY KEY CLUSTERED
(
[SectionId] ASC,
[UserId] ASC
)
CREATE TABLE [dbo].[aspnet_Users](
[ApplicationId] [uniqueidentifier] NOT NULL,
[UserId] [uniqueidentifier] NOT NULL,
[UserName] [nvarchar](256) NOT NULL,
[LoweredUserName] [nvarchar](256) NOT NULL,
[MobileAlias] [nvarchar](16) NULL,
[IsAnonymous] [bit] NOT NULL,
[LastActivityDate] [datetime] NOT NULL,
PRIMARY KEY NONCLUSTERED
(
[UserId] ASC
)
I omitted the foreign keys for brevity, but essentially this boils down to:
A Class can have many Sections.
A Section can belong to only 1 Class but can have many Students.
A Student (aspnet_Users) can belong to many Sections.
I've setup the corresponding Model classes and Fluent NHibernate Mapping classes, all that is working fine.
Here's where I'm getting stuck. I need to write a query which will return the sections a student is enrolled in based on the student's UserId and the dates of the class.
Here's what I've tried so far:
1.
var sections = (from s in this.Session.Linq<Sections>()
where s.Class.StartDate <= DateTime.UtcNow
&& s.Class.EndDate > DateTime.UtcNow
&& s.Students.First(f => f.UserId == userId) != null
select s);
2.
var sections = (from s in this.Session.Linq<Sections>()
where s.Class.StartDate <= DateTime.UtcNow
&& s.Class.EndDate > DateTime.UtcNow
&& s.Students.Where(w => w.UserId == userId).FirstOrDefault().Id == userId
select s);
Obviously, 2 above will fail miserably if there are no students matching userId for classes the current date between it's start and end dates...but I just wanted to try.
The filters for the Class StartDate and EndDate work fine, but the many-to-many relation with Students is proving to be difficult. Everytime I try running the query I get an ArgumentNullException with the message:
Value cannot be null.
Parameter name: session
I've considered going down the path of making the SectionStudents relation a Model class with a reference to Section and a reference to Student instead of a many-to-many. I'd like to avoid that if I can, and I'm not even sure it would work that way.
Thanks in advance to anyone who can help.
Ryan
For anyone who cares, it looks like the following might work in the future if Linq-To-NHibernate can support subqueries (or I could be totally off-base and this could be a limitation of the Criteria API which is used by Linq-To-NHibernate):
var sections = (from s in session.Linq<Section>()
where s.Class.StartDate <= DateTime.UtcNow
&& s.Class.EndDate > DateTime.UtcNow
&& s.Students.First(f => f.UserId == userId) != null
select s);
However I currently receive the following exception in LINQPad when running this query:
Cannot use subqueries on a criteria
without a projection.
So for the time being I've separated this into 2 operations. First get the Student and corresponding Sections and then filter that by Class date. Unfortunately, this results in 2 queries to the database, but it should be fine for my purposes.

Categories

Resources