Regarding my table as below
WORKING_CALENDAR_TABLE
===================================================
EMPLOYEE ID | DATE | WORKING DAY (0: Holiday; 1: WORKING DAY)
===================================================
02661 2017/12/01 1
02661 2017/12/02 1
02661 2017/12/03 0
02661 2017/12/04 0
02661 2017/12/05 0
02661 2017/12/06 1
02661 2017/12/07 1
02661 2017/12/08 1
02661 2017/12/09 1
When 2017/12/10, my expected result as below
===================================================
EMPLOYEE ID | CONTINOUS WORKING DAY
===================================================
02661 4
IF WE USE SQL ORACLE, CAN WE UTILIZE SQL ORACLE to got this result ?
One way of doing it can be by:
Getting the last day before your reference date (2017/12/10) where the employee didn´t work.
Counting the rows after the date in 1. and before your reference date. Forcibly, each row represents a working day for the employee.
Here's the code with some comments:
Select employee_id, count(*) as continuous_days from mytable
where employee_id = '02661' and date > (select max(date)
where employee_id ='02661' and working_day = 0 and date date <
'2017/12/10') and date <
'2017/12/10' group by employee_id
/* (select max(date)
where employee_id ='02661' and working_day = 0 and date <
'2017/12/10') gets the last day where the employee didn't work before the reference date. Each row from a date after max(date) represent a working day for the employee because all of them are going to to have working_day = 1*/
Something to improve here:
In the case the employee had no holidays before a reference date then
select max(date)
where employee_id ='02661' and working_day = 0 and date date <
'2017/12/10' will return null so you could use COALESCE to prevent errors and in the case of a null, you get some other value in return. I think that in your case it would suffice with a very early date. You could use it this way:
COALESCE( (select max(date)
where employee_id ='02661' and working_day = 0 and date <
'2017/12/10'), '1900-01-01')
and the complete query would be:
select employee_id, count(*) as continuous_days from mytable
where employee_id = '02661' and date > COALESCE( (select max(date)
where employee_id ='02661' and working_day = 0 and date <
'2017/12/10'), '1900-01-01') and date <
'2017/12/10' group by employee_id
For a given date, the most general solution is:
select employee_id, count(*)
from t
where employee_id = '02661' and
date < date '2017-12-10' and
date > (select max(t2.date)
from t t2
where t2.employee_id = t.employee_id and t2.date < date '2017-12-10'
);
You can try this query:
SELECT T.EMPLOYEE_ID,
COUNT(0) AS CONTINUOUS_DAYS
FROM WORKING_CALENDAR_TABLE T
WHERE T.WORK_DATE BETWEEN (SELECT MAX(WORK_DATE) + 1
FROM WORKING_CALENDAR_TABLE I
WHERE I.EMPLOYEE_ID = T.EMPLOYEE_ID
AND I.WORK_DAY = 0)
AND DATE '2017-12-10' + 1
GROUP BY T.EMPLOYEE_ID
Related
I try to figure out, how I can get the penultimate workingday from todays date.
In my query, I would like to add an where clause where a specific date is <= today´s date minus 2 working days.
Like:
SELECT
SalesAmount
,SalesDate
FROM mytable t
JOIN D_Calendar c ON t.Date = c.CAL_DATE
WHERE SalesDate <= GETDATE()- 2 workingdays
I have a calendar table with a column "isworkingDay" in my database and I think i have to use this but i don´t know how?!
Structure of this table is like:
CAL_DATE
DayIsWorkDay
2022-07-28
1
2022-07-29
1
2022-07-30
0
2022-07-31
0
2022-08-01
1
One example: Today is Monday, August 01, 2022. So based on today, I need to get Thursday, July 28 2022.
My desired result in the where clause should get me something like this:
where SalesDate<= Getdate() minus 2 workingdays
Thanks for your ideas!
You could use something like this:
SELECT t.SalesDate,
PreviousWorkingDay = d.CAL_DATE
FROM mytable t
CROSS APPLY
( SELECT c.CAL_DATE
FROM D_Calendar AS c
WHERE c.CAL_DATE < t.SalesDate
AND c.DayIsWorkDay = 1
ORDER BY c.CAL_DATE DESC OFFSET 1 ROWS FETCH NEXT 1 ROW ONLY
) AS d;
It uses OFFSET 1 ROWS within the CROSS APPLY to get the penultimate working day
This is how i implemented the idea from #SMor:
SELECT
SalesAmount
,SalesDate
FROM mytable t
JOIN D_Calendar c ON t.Date = c.CAL_DATE
WHERE SalesDate <= (SELECT
MIN(t1.CAL_DATE) as MinDate
FROM
(SELECT TOP 2
[CAL_DATE]
FROM [DWH_PROD].[cbi].[D_Calendar]
WHERE CAL_DAYISWORKDAY = 1 AND CAL_DATE < DATEADD(dd,0,DATEDIFF(dd,0,GETDATE()))
ORDER BY CAL_DATE DESC
) t1)
Thank you for your ideas and recommendations!
You can use a ROW_NUMBER() OVER(ORDER BY CAL_DATE desc) getting get the top 2 rows then take the row with number 2.
Example:
-- setup
Declare #D_Calendar as Table (CAL_DATE date, DayIsWorkDay bit)
insert into #D_Calendar values('2022-07-27', 1)
insert into #D_Calendar values('2022-07-28', 1)
insert into #D_Calendar values('2022-07-29', 1)
insert into #D_Calendar values('2022-07-30', 0)
insert into #D_Calendar values('2022-07-31', 0)
insert into #D_Calendar values('2022-08-01', 1)
Declare #RefDate DateTime = '2022-08-01 10:00'
-- example query
Select CAL_DATE
From
(Select top 2 ROW_NUMBER() OVER(ORDER BY CAL_DATE desc) AS BusinessDaysBack, CAL_DATE
from #D_Calendar
where DayIsWorkDay = 1
and CAL_DATE < Cast(#RefDate as Date)) as Data
Where BusinessDaysBack = 2
From there you can plug that into your where clause to get :
SELECT
SalesAmount
,SalesDate
FROM mytable t
WHERE SalesDate <= (Select CAL_DATE
From (Select top 2 ROW_NUMBER() OVER(ORDER BY CAL_DATE desc) AS BusinessDaysBack, CAL_DATE
from D_Calendar
where DayIsWorkDay = 1
and CAL_DATE < Cast(getdate() as Date)) as Data
Where BusinessDaysBack = 2)
Change the 2 to 3 to go three days back etc
I have this statement that works, but it's unbridled, as in it SUMs up the whole column, I want introduce date range but I'm getting an error.
HERE IS WHAT IS WORKING
UPDATE payroll_employee e
SET hours = l.total
FROM (SELECT employee, SUM(end_date - start_date) AS total
FROM payroll_timelog
GROUP BY employee) l
WHERE e.id = l.employee
I want to introduce a date filter.
Then I tried this CTE,
WITH cte AS (
SELECT employee_id, end_date SUM(end_date - start_date) AS total
FROM payroll_timelog
WHERE employee_id = 1, AND end_date > 2020-09-01
)
UPDATE payroll_employee e
SET hours = total
FROM cte
WHERE e.id = 1;
Tried casting date to 2020-09-01::date, 2020-09-01::timestamp etc, still won't work. any help will be appreciated.
I think you just have syntax errors:
WITH cte AS (
SELECT employee_id, SUM(end_date - start_date) AS total
FROM payroll_timelog
WHERE employee_id = 1 AND end_date > '2020-09-01'
GROUP BY employee_id
)
UPDATE payroll_employee e
SET hours = cte.total
FROM cte
WHERE e.id = 1;
I'm fairly new to SQL and I'm using BigQuery to find customers who purchased in 2019 and 2018.
This is the query I'm using to find the customers who purchased in 2019.
SELECT DISTINCT contact_email
FROM (
SELECT *, ROW_NUMBER() OVER(PARTITION BY id) AS instance
FROM `table.orders`
) orders -- identify duplicate rows
WHERE
instance = 1
AND processed_at between '2019-01-01 00:00:00 UTC' AND '2020-01-01 00:00:00 UTC'
I'm struggling now with how to pull in distinct users who purchased this year AND last year. Can anyone point me in the correct direction? Thank you.
Hmmm. I think I might do this as an aggregation query:
select o.contact_email
from `table.orders o`
where instance = 1 and
processed_at >= timestamp('2018-01-01') and
processed_at < timestamp('2020-01-01')
group by o.contact_email
having count(distinct year(processed_at)) = 2;
You can use aggregation:
select contact_email
from `table.orders`
where
instance = 1
and processed_at >= timestamp('2018-01-01')
and processed_at < timestamp('2020-01-01')
group by contact_email
having
max(case
when processed_at >= timestamp('2019-01-01')
and processed_at < timestamp('2020-01-01')
then 1 end
) = 1
and max(case
when processed_at >= timestamp('2018-01-01')
and processed_at < timestamp('2019-01-01')
then 1 end
) = 1
How do we select the count of the record that appears more than once in 48hrs?
for eg
ID DATE
1 9/24/2018
1 9/23/2018
1 9/20/2018
2 9/20/2018
ID 1 APPEARED MORE THAN ONCE IN 48 HOURS
please let me know how to write a sql query to do this
There are lots of ways, but I'd start with using LAG() and a date comparison. Assuming your DATE column is a date data-type?
WITH
entity_summary AS
(
SELECT
ID,
CASE
WHEN LAG("DATE") OVER (PARTITION BY ID ORDER BY "DATE") >= "DATE" - INTERVAL '2' DAY
THEN 1
ELSE 0
END
AS occurence_within_2_day
FROM
Table1
)
SELECT
ID,
SUM(occurence_within_2_day)
FROM
entity_summary
GROUP BY
ID
HAVING
SUM(occurence_within_2_day) >= 1
Sorry for confusing title. Please, tell, if it's possible to do via db request. Assume we have following table
ind_id name value date
----------- -------------------- ----------- ----------
1 a 10 2010-01-01
1 a 20 2010-01-02
1 a 30 2010-01-03
2 b 10 2010-01-01
2 b 20 2010-01-02
2 b 30 2010-01-03
2 b 40 2010-01-04
3 c 10 2010-01-01
3 c 20 2010-01-02
3 c 30 2010-01-03
3 c 40 2010-01-04
3 c 50 2010-01-05
4 d 10 2010-01-05
I need to query all rows to include each ind_id once for the given date, and if there's no ind_id for given date, then take the nearest lower date, if there's no any lower dates, then return ind_id + name (name/ind_id pairs are equal) with nulls.
For example, date is 2010-01-04, I expect following result:
ind_id name value date
----------- -------------------- ----------- ----------
1 a 30 2010-01-03
2 b 40 2010-01-04
3 c 40 2010-01-04
4 d NULL NULL
If it's possible, I'll be very grateful if someone help me with building query. I'm using SQL server 2008.
Check this SQL FIDDLE DEMO
with CTE_test
as
(
select int_id,
max(date) MaxDate
from test
where date<='2010-01-04 00:00:00:000'
group by int_id
)
select A.int_id, A.[Value], A.[Date]
from test A
inner join CTE_test B
on a.int_id=b.int_id
and a.date = b.Maxdate
union all
select int_id, null, null
from test
where int_id not in (select int_id from CTE_test)
(Updated) Try:
with cte as
(select m.*,
max(date) over (partition by ind_id) max_date,
max(case when date <= #date then date end) over
(partition by ind_id) max_acc_date
from myTable m)
select ind_id,
name,
case when max_acc_date is null then null else value end value,
max_acc_date date
from cte c
where date = coalesce(max_acc_date, max_date)
(SQLFiddle here)
Here is a query that returns the result that you are looking for:
SELECT
t1.ind_id
, CASE WHEN t1.date <= '2010-01-04' THEN t1.value ELSE null END
FROM test t1
WHERE t1.date=COALESCE(
(SELECT MAX(DATE)
FROM test t2
WHERE t2.ind_id=t1.ind_id AND t2.date <= '2010-01-04')
, t1.date)
The idea is to pick a row in a correlated query such that its ID matches that of the current row, and the date is the highest one prior to your target date of '2010-01-04'.
When such row does not exist, the date for the current row is returned. This date needs to be replaced with a null; this is what the CASE statement at the top is doing.
Here is a demo on sqlfiddle.
You can use something like:
declare #date date = '2010-01-04'
;with ids as
(
select distinct ind_id
from myTable
)
,ranks as
(
select *
, ranking = row_number() over (partition by ind_id order by date desc)
from myTable
where date <= #date
)
select ids.ind_id
, ranks.value
, ranks.date
from ids
left join ranks on ids.ind_id = ranks.ind_id and ranks.ranking = 1
SQL Fiddle with demo.
Ideally you wouldn't be using the DISTINCT statement to get the ind_id values to include, but I've used it in this case to get the results you needed.
Also, standard disclaimer for these sorts of queries; if you have duplicate data you should consider a tie-breaker column in the ORDER BY or using RANK instead of ROW_NUMBER.
Edited after OPs update
Just add the new column into the existing query:
with ids as
(
select distinct ind_id, name
from myTable
)
,ranks as
(
select *
, ranking = row_number() over (partition by ind_id order by date desc)
from myTable
where date <= #date
)
select ids.ind_id
, ids.name
, ranks.value
, ranks.date
from ids
left join ranks on ids.ind_id = ranks.ind_id and ranks.ranking = 1
SQL Fiddle with demo.
As with the previous one it would be best to get the ind_id/name information through joining to a standing data table if available.
Try
DECLARE #date DATETIME;
SET #date = '2010-01-04';
WITH temp1 AS
(
SELECT t.ind_id
, t.name
, CASE WHEN t.date <= #date THEN t.value ELSE NULL END AS value
, CASE WHEN t.date <= #date THEN t.date ELSE NULL END AS date
FROM test1 AS t
),
temp AS
(
SELECT *, ROW_NUMBER() OVER (PARTITION BY ind_id ORDER BY t.date DESC) AS rn
FROM temp1 AS t
WHERE t.date <= #date OR t.date IS NULL
)
SELECT *
FROM temp AS t
WHERE rn = 1
Use option with EXISTS operator
DECLARE #date date = '20100104'
SELECT ind_id,
CASE WHEN date <= #date THEN value END AS value,
CASE WHEN date <= #date THEN date END AS date
FROM dbo.test57 t
WHERE EXISTS (
SELECT 1
FROM dbo.test57 t2
WHERE t.ind_id = t2.ind_id AND t2.date <= #date
HAVING ISNULL(MAX(t2.date), t.date) = t.date
)
Demo on SQLFiddle
This is not the exact answer but will give you the concept as i just write it down quickly without any testing.
use
go
if
(Select value from table where col=#col1) is not null
--you code to get the match value
else if
(Select LOWER(Date) from table ) is not null
-- your query to get the nerst dtae record
else
--you query withh null value
end