SELECT records that were not yesterday - sql-server

I have the following CTE
;
WITH cte
AS
(
select t.UserId, t.Date
from (select
Date
, UserId
, row_number() over(partition by UserId order by Date desc) as RowNumber
from dbo.Income_Expenses) as t
where t.RowNumber = 1
)
If I make a selection on it, I'll get the following results:
Date UserId RowNumber
2015-05-10 00:00:00.000 6 1
2015-05-08 00:00:00.000 7 1
Basically I get the last record that has been inserted by every user.
Now, when I make a selection on the CTE, I want to get the records that are older than the day before yesterday.
I.E. Today is May 10th; I want all the records that are from May 8th and later. (8th, 7th, etc, but not 9th and 10th).
So I tried some expression with DATEADD, DATEDIFF and none of them worked.
Can someone help me?

Try to add this condition to the cte: and datediff(day, date, getDate()) >= 2

Related

How to create a week counter?

Example of what I am trying to do:
I have 10 employees. They all started on different days throughout the year. Each potentially gets paid once a week. I want to query their first paycheck and call that week 1 for all employees. Then each subsequent paycheck will be 2...3...through 13. So basically I want to see what each of their first 13 weeks on the job looked like stacked against each other. The catch here is the potentially above. Employees might not get paid each week so I would want to see a zero for that week. I know this is tough because there is no record to read for that week. I would expect my output to look something like this:
I was thinking of using a Tally Table of some kind and reading their hire date +7 over an over? I am open to any idea.
You can use Row_Number() as shown below.
SELECT Week
,EmployeeId
,[Paycheck Date]
,Amount
,Row_Number() OVER (
PARTITION BY EmployeeId ORDER BY [Paycheck Date]
) AS WkNo
FROM Yourtable
To create and join with the Week Number table you can try something as shown below.
;WITH WeekTable(n) AS
(
SELECT 1
UNION ALL
SELECT n + 1 FROM WeekTable WHERE n < 52
)
SELECT
n
FROM WeekTable
left join (SELECT Week
,EmployeeId
,[Paycheck Date]
,Amount
,Row_Number() OVER (
PARTITION BY EmployeeId ORDER BY [Paycheck Date]
) AS WkNo
FROM Yourtable)emp on n = emp.WkNo
ORDER BY n
OPTION (MAXRECURSION 1000);

How can i remove duplicate rows with in my sql server database

I have this table of attendance system with columns dateinout, checkin, checkout etc. user punch in when come to office and punch out when go out. system retrieve data two time from fingerprint scanner machine. I want to delete rows with more than one count in same date where punch in is between 7am to 11 am also the rows with check out with same date in between 11 am to 6 pm.
SELECT
a.Logid,
a.Userid,
a.CheckTime,
a.Name
FROM Checkinout a
JOIN
(SELECT
userid,
name,
dateinout,
Intime,
Outtime
FROM att
WHERE Intime BETWEEN '07:00:00.0000000' AND '11:00:00.0000000'
AND userid= 37
GROUP BY userid, dateinout, Intime, Outtime, name
HAVING COUNT(Intime)>1) b
ON a.Userid= b.userid
ORDER BY CheckTime ASC;
You can use cte to delete duplicates from the att table based on your grouping criteria.
;WITH CTE AS(
SELECT
row_number() over (partition by userid,dateinout, Intime, Outtime order by date) AS ROWNUMBER,
userid,
dateinout,
Intime,
Outtime
FROM
att
WHERE
Intime BETWEEN '07:00:00.0000000' AND '11:00:00.0000000'
AND userid = 37
)
DELETE FROM CTE WHERE ROWNUMBER>1
You can do step by step.
Firstly, find insert count in time range:
SELECT COUNT(Logid), userid
FROM Checkinout
WHERE Intime BETWEEN '07:00:00.0000000' AND '11:00:00.0000000'
GROUP BY Logid
HAVING COUNT(Logid) > 1
after, you got list, you can distract by property how you need

T-SQL select values grouped by week, zero if no values present for week

I am trying to group values (sales data) by week in SQL Server. For items with no sales in a certain week, I still want to get the week number and year, with a sum of 0.
The sales ledger table has computed columns for year and week number, by which I group.
Right now my Query looks like this:
select ItemNumber, sum(Amount), year, week
from JournalPosition
group by week, year, ItemNumber
order by ItemNumber asc, year desc, week desc
What would be an efficient way to accomplish what i want without having to implement a data warehouse? (Stored procedure or temporary table would be fine for me)
You need to generate a list of all of the weeks that you want to include in your query and join onto it. You can either store these in a pre-generated table or use a CTE. Something like this will help you with a CTE how to get the start and end dates of all weeks between two dates in SQL server?
You can use recursive CTE with dates from your table:
declare #StartDate datetime,#EndDate datetime
set #StartDate=(select convert(varchar,min(Year),102) from JournalPosition)
set #EndDate=(select dateadd(day,-1,dateadd(year,2,convert(varchar,max(Year),102))) from JournalPosition)
print #StartDate
print #EndDate
;with CTE as (
select #StartDate as StartDate, DATEPART(week,#StartDate) as WeekNumber, DATEPART(year,#StartDate) as YearNumber
union all
select DATEADD(week, 1, StartDate), DATEPART(week,DATEADD(WEEK, 1, StartDate)), DATEPART(year,DATEADD(week, 1, StartDate))
from CTE
where DATEADD(week, 1, StartDate) <= #EndDate
)
select ItemNumber, isnull(sum(Amount),0), CTE.YearNumber, datepart(week,CTE.StartDate)
from JournalPosition
full join CTE
on JournalPosition.week=datepart(week,CTE.StartDate) and JournalPosition.year=CTE.YearNumber
group by CTE.YearNumber, datepart(week,CTE.StartDate), ItemNumber
order by 3 desc, 4 desc, 1 asc
option (maxrecursion 32767);
But maybe it's better not to use recursion (see http://www.sqlservercentral.com/Forums/Topic779830-338-1.aspx).

Incement value of datetime field

I am using SQLServer2008R2. I have a column called RunningDate.
What I want is if today I set value of RunningDate as 2013-08-13 00:00:00.000 then tomorrow it will be updated automatically as 2013-08-14 00:00:00.000.
I know about DATEADD function but how to use it in above scenario?
Any help would be appreciated. Thanks.
You have two options:
Option A
Leave the RunningDate column out of your table and create a view instead. Add the RunningDate column to the view as CAST(CAST(GETDATE() AS DATE) AS DATETIME).
Option B
Create a SQL Server Agent job that updates the table periodically at midnight. Remember to strip out the time portion of the date (for example using the casts in Option A), as you can never be sure that the statement runs exactly at 00:00:00.000.
Try this one -
DECLARE #temp TABLE
(
ID INT PRIMARY KEY
, RunningDate DATETIME
)
INSERT INTO #temp (ID)
VALUES (1),(2),(3),(5),(8)
UPDATE tt
SET RunningDate = CAST(DATEADD(dd, t.rn, GETDATE()) AS DATE)
FROM #temp tt
JOIN (
SELECT
ID
, rn = ROW_NUMBER() OVER (ORDER BY 1/0) - 1
FROM #temp
) t ON t.ID = tt.ID
SELECT *
FROM #temp
Output -
ID RunningDate
----------- -----------------------
1 2013-08-13 00:00:00.000
2 2013-08-14 00:00:00.000
3 2013-08-15 00:00:00.000
5 2013-08-16 00:00:00.000
8 2013-08-17 00:00:00.000
I would suggest not adding it into a database if it's only one field. If you are going to use it in stored procedure then use
SELECT GETDATE()
OR
SELECT DATEADD(day, DATEDIFF(day, '19000101', GETDATE()), '19000101');
to match or DateTime.Now in your code - If it's .NET. You will be adding a lot of overhead just by storing one entry into a table.

Identify ranges in groups which are identified by a flag

I have the following table:
declare #table table (dates int , is_missing tinyint, group_id numeric(18))
insert into #table(dates,is_missing,group_id)
select 20110719,0,1
union all
select 20110720,0,1
union all
select 20110721,0,1
union all
select 20110722,1,1
union all
select 20110723,0,1
union all
select 20110724,0,1
union all
select 20110725,0,1
union all
select 20110726,1,1
union all
select 20110727,0,1
union all
select 20110728,1,1
union all
select 20110723,1,3
union all
select 20110724,0,3
union all
select 20110725,0,3
union all
select 20110726,1,3
union all
select 20110727,0,3
select * from #table
order by group_id, dates
What I am trying to do is to return ranges of dates for each group which are identified by the missing day flag. To make this more clear the results of the query will have to look like this:
group_id start_date end_date days_count
1 20110719 20110721 3
1 20110723 20110725 3
1 20110727 20110727 1
3 20110724 20110725 2
3 20110727 20110727 1
The is_missing flag basicaly separates the ranges per group. It actually says that a date is missing and therefore all the other dates located between is_missing flags are the groups I am trying to find their start and end dates as well as their days numbers count.
Is there a simple way to do this?
Thanks a lot.
Here is a possible solution using Common Table Expression (CTE) and ROW_NUMBER(). This type of problem is known as islands. Using the concept that was used in this Stack Overflow question: sql group by only rows which are in sequence, the following query was formulated to produce desired output against the data provided by you.
This query works correctly if the data stored in the table is ordered by group_id and dates columns. I assume that is the case with your data. If not, you might need to tweak the solution.
Modified the query as per suggestions provided by Andriy M. Thanks to Andriy M.
The query has been changed so that it can provide correct output even if the date values in the table are not in sequence. The question has the date values stored in int data type instead of date format. So, two queries have been provided below. First query will work if the table contains date values stored in int data typeand the second query will work if the table contains date values stored in datetime or date data type.
This query will work only in SQL Server versions 2005 and above. Since you have tagged your question under sql-server-2008, I think this should work for you.
Screenshot #1 displays the data stored in the table. Screenshot #2 displays the output of the below mentioned queries against the table data.
Hope that helps.
Query for date values stored in int data type:
.
WITH cte AS
(
SELECT datenumeric
, is_missing
, group_id
, datenumeric
- DENSE_RANK() OVER (PARTITION BY is_missing ORDER BY group_id, datenumeric) AS partition_grp
FROM dbo.table_data
)
SELECT cte.group_id
, MIN(cte.datenumeric) AS start_date
, MAX(cte.datenumeric) AS end_date
, COUNT(cte.datenumeric) AS days_count
FROM cte
WHERE cte.is_missing = 0
GROUP BY cte.group_id
, cte.partition_grp
ORDER BY cte.group_id
, cte.partition_grp;
Query for date values stored in datetime or date data type:
.
WITH cte AS
(
SELECT datevalue
, is_missing
, group_id
, DATEDIFF(DAY, 0, datevalue)
- DENSE_RANK() OVER (PARTITION BY is_missing ORDER BY group_id, datevalue) AS partition_grp
FROM dbo.table_data
)
SELECT cte.group_id
, MIN(cte.datevalue) AS start_date
, MAX(cte.datevalue) AS end_date
, COUNT(cte.datevalue) AS days_count
FROM cte
WHERE cte.is_missing = 0
GROUP BY cte.group_id
, cte.partition_grp
ORDER BY cte.group_id
, cte.partition_grp;
Screenshot #1:
Screenshot #2:
With many thanks to Siva for the nice solution, I thought if there was one date missing in the data, the query would fail.
so I modified the query a little and used ROW_NUMBER() to fix that.
WITH cte AS
(
SELECT dates
, is_missing
, group_id
,ROW_NUMBER() OVER (ORDER BY group_id, dates) -
DENSE_RANK() OVER (PARTITION BY is_missing ORDER BY group_id, dates) AS partition_Id
FROM dbo.table_data
)
SELECT group_id
, MIN(dates) AS start_date
, MAX(dates) AS end_date
, COUNT(*) AS days_count
FROM cte
WHERE is_missing = 0
GROUP BY group_id
, partition_id
ORDER BY group_id
, partition_id;
Or maybe a missing date will never happen. :)

Resources