Max Date where another column value equals FALSE only not TRUE - sql-server-2012

I have a table
emp_id Visit Date non_billable
1 5/2/2021 FALSE
1 5/5/2021 FALSE
1 5/6/2021 TRUE
Tried something similar to this:
Measure =
VAR LatestDate =
CALCULATE ( MAX ( 'Table1'[visit_date] ), ALL ( 'Table1' ) )
RETURN
( ( 'Table1'[non_billable] ) = FALSE )
Trying to find the MAX date for visit_date where non_billable = FALSE
So for emp_id = 1 Max Date would be 5/5/2021 not 5/6/2021

you can use the window function like below.
use case expression to check for non_billable = FALSE
max(case when non_billable = 'FALSE' then visit_date end) over (partition by empid)

Answered thank you:
Measure:
Max_Date = CALCULATE(MAX(vwQLK_999_ClientVisit[visit_date]),vwQLK_999_ClientVisit[non_billable]=FALSE())

Related

CASE WHEN condition with MAX() function

There are a lot questions on CASE WHEN topic, but the closest my question is related to this How to use CASE WHEN condition with MAX() function query which has not been resolved.
Here is some of my sample data:
date
debet
2022-07-15
57190.33
2022-07-14
815616516.00
2022-07-15
40866.67
2022-07-14
1221510.00
So, I want to all records for the last two dates and three additional columns: sum(sales) for the previous day, sum for the current day and the difference between them:
SELECT
[debet],
[date] ,
SUM( CASE WHEN [date] = MAX(date) THEN [debet] ELSE 0 END ) AS sum_act,
SUM( CASE WHEN [date] = MAX(date) - 1 THEN [debet] ELSE 0 END ) AS sum_prev ,
(
SUM( CASE WHEN [date] = MAX(date) THEN [debet] ELSE 0 END )
-
SUM( CASE WHEN [date] = MAX(date) - 1 THEN [debet] ELSE 0 END )
) AS diff
FROM
Table
WHERE
[date] = ( SELECT MAX(date) FROM Table WHERE date < ( SELECT MAX(date) FROM Table) )
OR
[date] = ( SELECT MAX(date) FROM Table WHERE date = ( SELECT MAX(date) FROM Table ) )
GROUP BY
[date],
[debet]
Further, of course, it informs that I can't use the aggregate function inside CASE WHEN. Now I use this combination: sum(CASE WHEN [date] = dateadd(dd,-3,cast(getdate() as date)) THEN [debet] ELSE 0 END). But here every time I need to make an adjustment for weekends and holidays. The question is, is there any other way than using 'getdate' in 'case when' Statement to get max date?
Expected result:
date
sum_act
sum_prev
diff
2022-07-15
97190.33
0.00
97190.33
2022-07-14
0.00
508769.96
-508769.96
You can use dense_rank() to filter the last 2 dates in your table. After that you can use either conditional case expression with sum() to calculate the required value
select [date],
sum_act = sum(case when rn = 1 then [debet] else 0 end),
sum_prev = sum(case when rn = 2 then [debet] else 0 end),
diff = sum(case when rn = 1 then [debet] else 0 end)
- sum(case when rn = 2 then [debet] else 0 end)
from
(
select *, rn = dense_rank() over (order by [date] desc)
from tbl
) t
where rn <= 2
group by [date]
db<>fiddle demo
Two steps:
Get the sums for the last three dates
Show the results for the last two dates.
Well, we could also get all daily sums in step 1, but we just need the last three in order to calculate the sums for the last two days, so why aggregate more data than necessary?
Here is the query. You may have to put the date column name in brackets in SQL Server, as date is a keyword in SQL.
select top(2)
date,
sum_debit_current,
sum_debit_previous,
sum_debit_current - sum_debit_previous as diff
(
select
date,
sum(debet) as sum_debit_current,
lag(sum(debet)) over (order by date) as sum_debit_previous
from table
where date in (select distinct top(3) date from table order by date desc)
group by date
)
order by date desc;
(SQL Server uses TOP(n) instead of standard SQL FETCH FIRST 3 ROWS and while SELECT DISTINCT TOP(3) date looks like "get the top 3 rows, then apply distinct on their date", it is really "apply distinct on the dates, then get the top 3" like in standard SQL.)

How to select count of 0s, 1s, and both 0s and 1s in a postgres table column?

Say there's a table that has columns named binary_value, name, and created_at along with the id column.
Here's the SQL Fiddle for this question: http://sqlfiddle.com/#!15/d15d1/36
What would be an efficient query to get a result like the following?
ones_count | zeros_count | total
3 | 1 | 4
So far, I've got:
with cte2(count_type, counted) as (
with cte as (
select binary_value,
sum(case when binary_value = 1 then 1 else 0 end) as ones_count,
sum(case when binary_value = 0 then 1 else 0 end) as zeros_count
from infos
where name = 'me'
and created_at >= '2020-03-10 21:13:01.319677'
and created_at <= '2020-03-10 21:13:01.619677'
group by binary_value
)
select 'ones_count', ones_count from cte where binary_value = 1
union
select 'ones_count', zeros_count from cte where binary_value = 0
union
select 'total', sum(ones_count + zeros_count) as total from cte
)
select * from cte2;
Which gives it in column form:
count_type | counted
ones_count | 1
total | 4
ones_count | 3
How can we get the result in a row? Perhaps there's a different approach altogether than Common Table Expression? I'm starting to look at crosstab, which is postgres-specific, and so wondering if all this is overkill.
Including DDL and data here, too:
create table infos (
id serial primary key,
name character varying not null,
binary_value integer not null,
created_at timestamp without time zone not null
)
insert into infos ("binary_value", "name", "created_at") values
(1, 'me', '2020-03-10 21:13:01.319677'),
(1, 'me', '2020-03-10 21:13:01.419677'),
(0, 'me', '2020-03-10 21:13:01.519677'),
(1, 'me', '2020-03-10 21:13:01.619677');
I think you just want conditional aggregation:
select count(*) filter (where binary_value = 0) as num_0s,
count(*) filter (where binary_value = 1) as num_1s,
count(*)
from infos
where name = 'me' and
created_at >= '2020-03-10 21:13:01.319677' and
created_at <= '2020-03-10 21:13:01.619677';
The date comparison looks rather, uh, specific. I assume that you really intend a range there.
Here is a SQL Fiddle.
Note: If you are really using Postgres 9.3, then you can't use the filter clause (alas). Instead:
select sum( (binary_value = 0)::int ) as num_0s,
sum( (binary_value = 1)::int ) as num_1s,
count(*)
from infos
where name = 'me' and
created_at >= '2020-03-10 21:13:01.319677' and
created_at <= '2020-03-10 21:13:01.619677';
Also, if you wanted the results in three separate rows, a simpler query is:
select binary_value, count(*)
from infos
where name = 'me' and
created_at >= '2020-03-10 21:13:01.319677' and
created_at <= '2020-03-10 21:13:01.619677'
group by grouping sets ( (binary_value), () );
Much simpler:
select
sum(case when binary_value = 1 then 1 else 0 end) as ones_count,
sum(case when binary_value = 0 then 1 else 0 end) as zeroes_count,
count(*) as total
from infos

SQL query min and max group by flag

I have a table as below :
How can I craft a SQL select statement so that MIN AND MAX EVENT DATE groups results by FLAG (0,1)?
So the result would be:
Just do conditional aggregation with use of window function
SELECT card_no, descr_reader,
max(CASE WHEN flag = 0 THEN event_date END) date_in,
max(CASE WHEN flag = 1 THEN event_date END) date_out
FROM
(
SELECT *,
COUNT(flag) OVER (PARTITION BY flag ORDER BY id) Seq
FROM table t
)t
GROUP BY card_no, descr_reader, Seq
An alternative if Window function does not work:
SELECT
t1.card_no, t1.descr_reader,
t1.event_date date_in,
(select top 1 event_date from test t2
where t2.card_no = t1.card_no and
t2.reader_no = t1.reader_no and
t2.descr_reader = t1.descr_reader and
t2.event_date > t1.event_date and
t2.flag = 1
order by t2.event_date ) as date_out
FROM test t1
WHERE t1.flag = 0

Inline Table Join Multiplying Results

The below query joins two views and one inline table to another inline table. When I run the query without table FI all of the SUM values return correctly, however, when I run the query with table FI all of the SUM values from vw_Interactions are multiplied and returned incorrect (SUM values from vw_LeadInteractions are not affected).
vw_Interactions is a transactional log and returns a 1 in each column where that measure is true (ex: a 1 is returned in I.[Call] where a phone call was logged), and vw_LeadInteractions is the same except it returns the Client's ID.
I did several hours of research and found that inline tables can cause issues when joining (the Cartesian product?), however I wasn't able to understand how those answers were relevant to this query.
Can someone explain why that when table FI is included in this query that it multiplies the SUM values of everything from vw_Interactions? And then how do I fix my query so this does not happen?
This query is for my employer's outbound call center to measure what's happening during each 'round' of calling.
/* Parameters */
DECLARE #StartDatetime AS Date
SET #StartDatetime = '06/01/13'
DECLARE #EndDatetime AS Date
SET #EndDatetime = '05/31/14'
/* Dataset */
SELECT R.[RoundsGoal]
,R.[RoundNumber]
,COUNT(DISTINCT R.[Client_Id]) AS 'Leads'
,ISNULL(SUM(I.[Call]), 0) AS 'Calls'
,ISNULL(COUNT(DISTINCT LI.[Call]), 0) AS 'CallLeads'
,ISNULL(SUM(FI.[FirstCall]), 0) AS 'FirstCalls'
,ISNULL(SUM(I.[DecisionMakerCall]), 0) AS 'DecisionMakerCalls'
,ISNULL(COUNT(DISTINCT LI.[DecisionMakerCall]), 0) AS 'DecisionMakerCallLeads'
,ISNULL(SUM(FI.[FirstDecisionMakerCall]), 0) AS 'FirstDecisionMakerCalls'
,ISNULL(SUM( I.[LeftMessageCall]), 0) AS 'LeftMessageCalls'
,ISNULL(COUNT(DISTINCT LI.[LeftMessageCall]), 0) AS 'LeftMessageLeads'
,ISNULL(SUM(FI.[FirstLeftMessageCall]), 0) AS 'FirstLeftMessageCalls'
,ISNULL(SUM(I.[NoAnswerCall]), 0) AS 'NoAnswerCalls'
,ISNULL(COUNT(DISTINCT LI.[NoAnswerCall]), 0) AS 'NoAnswerCallLeads'
,ISNULL(SUM(FI.[FirstNoAnswerCall]), 0) AS 'FirstNoAnswerCalls'
FROM (
SELECT RD.[Client_Id]
,ISNULL(UF1.[NumericCol], 0) AS 'RoundsGoal'
,COUNT(RD.[RoundDate]) OVER(PARTITION BY RD.[Client_Id] ORDER BY RD.[RoundDate] ASC) AS 'RoundNumber'
,RD.[RoundDate]
FROM [dbo].[vw_RoundDates] RD
LEFT JOIN [dbo].[AMGR_User_Fields] UF1 ON RD.[Client_Id] = UF1.[Client_Id] AND UF1.[Type_Id] = 140 --Rounds Goal TypeId
LEFT JOIN [dbo].[AMGR_User_Field_Defs] UFD1 ON UF1.[Type_Id] = UFD1.[Type_Id] AND UF1.[Code_Id] = UFD1.[Code_Id]
WHERE RD.[RoundDate] >= #StartDatetime AND RD.[RoundDate] <= #EndDatetime
) R
LEFT JOIN [dbo].[vw_Interactions] I ON R.[Client_Id] = I.[Client_Id] AND R.[RoundDate] = CAST(I.[Created] AS DATE)
LEFT JOIN [dbo].[vw_LeadInteractions] LI ON R.[Client_Id] = LI.[Client_Id] AND R.[RoundDate] = CAST(LI.[Created] AS DATE)
LEFT JOIN (
SELECT I.[Client_Id]
,CASE WHEN (CASE WHEN I.[Call] = 1 THEN ROW_NUMBER() OVER(PARTITION BY I.[Client_Id], I.[Call] ORDER BY I.[Created] ASC) ELSE NULL END) = 1 THEN 1 ELSE NULL END AS 'FirstCall'
,CASE WHEN (CASE WHEN I.[DecisionMakerCall] = 1 THEN ROW_NUMBER() OVER(PARTITION BY I.[Client_Id], I.[DecisionMakerCall] ORDER BY I.[Created] ASC) ELSE NULL END) = 1 THEN 1 ELSE NULL END AS 'FirstDecisionMakerCall'
,CASE WHEN (CASE WHEN I.[LeftMessageCall] = 1 THEN ROW_NUMBER() OVER(PARTITION BY I.[Client_Id], I.[LeftMessageCall] ORDER BY I.[Created] ASC) ELSE NULL END) = 1 THEN 1 ELSE NULL END AS 'FirstLeftMessageCall'
,CASE WHEN (CASE WHEN I.[NoAnswerCall] = 1 THEN ROW_NUMBER() OVER(PARTITION BY I.[Client_Id], I.[NoAnswerCall] ORDER BY I.[Created] ASC) ELSE NULL END) = 1 THEN 1 ELSE NULL END AS 'FirstNoAnswerCall'
,[Created]
FROM [dbo].[vw_Interactions] I
) FI ON R.[Client_Id] = FI.[Client_Id] AND R.[RoundDate] = CAST(FI.[Created] AS DATE)
GROUP BY R.[RoundsGoal]
,R.[RoundNumber]
ORDER BY R.[RoundsGoal] ASC
,R.[RoundNumber] ASC
Here is the correct results set without table FI. Notice the Calls on row 23 equals 135,110.
Here is the incorrect results, that include table FI. Notice the Calls on row 23 are multiplied to 1,561,038.

counting events over flexible ranges

I am trying to count events (which are rows in the event_table) in the year before and the year after a particular target date for each person. For example, say I have a person 100 and target date is 10/01/2012. I would like to count events in 9/30/2011-9/30/2012 and in 10/02/2012-9/30/2013.
My query looks like:
select *
from (
select id, target_date
from subsample_table
) as i
left join (
select id, event_date, count(*) as N
, case when event_date between target_date-365 and target_date-1 then 0
when event_date between target_date+1 and target_date+365 then 1
else 2 end as after
from event_table
group by id, target_date, period
) as h
on i.id = h.id
and i.target_date = h.event_date
The output should look something like:
id target_date after N
100 10/01/2012 0 1000
100 10/01/2012 1 0
It's possible that some people do not have any events in the before or after periods (or both), and it would be nice to have zeros in that case. I don't care about the events outside the 730 days.
Any suggestions would be greatly appreciated.
I think the following may approach what you are trying to accomplish.
select id
, target_date
, event_date
, count(*) as N
, SUM(case when event_date between target_date-365 and target_date-1
then 1
else 0
end) AS Prior_
, SUM(case when event_date between target_date+1 and target_date+365
then 1
else 0
end) as After_
from subsample_table i
left join
event_table h
on i.id = h.id
and i.target_date = h.event_date
group by id, target_date, period
This is a generic answer. I don't know what date functions teradata has, so I will use sql server syntax.
select id, target_date, sum(before) before, sum(after) after, sum(righton) righton
from yourtable t
join (
select id, target_date td
, case when yourdate >= dateadd(year, -1, target_date)
and yourdate < target_date then 1 else 0 end before
, case when yourdate <= dateadd(year, 1, target_date)
and yourdate > target_date then 1 else 0 end after
, case when yourdate = target_date then 1 else 0 end righton
from yourtable
where whatever
group by id, target_date) sq on t.id = sq.id and target_date = dt
where whatever
group by id, target_date
This answer assumes that an id can have more than one target date.