In SQL server, how can I affect a value to an attribute given a condition, and check the condition everyday?
Let's say an order was recorded on a certain date. According to my business rule the delivery should be made no later than 10 days after the order date.
In my Delivery table, I have a status attribute.
In my Order table, I have an orderDate attribute.
I would like the status value to be set based on the following logic:
if deliveryDate is null:
if today's date < orderDate + 10:
'in progress'
else :
'late'
else :
if deliveryDate > orderDate + 10:
'late'
else:
'on time'
Is there a way I can do that, and update the status value everyday to check again if the order is late?
Use the case/when statement.
-- if deliveryDate is null:
-- if today's date < orderDate + 10:
-- 'in progress'
-- else :
-- 'late'
-- else :
-- if deliveryDate > orderDate + 10:
-- 'late' else: 'on time'
select
case
when tableName.deliveryDate is null
case
when datetimeutc() <= dateadd(tableName.orderDate, 10, 'dd')
then 'in progress'
else 'late'
end
else
case
when tableName.deliveryDate > dateadd(tableName.orderDate, 10, 'dd')
then 'late'
else 'on time'
end
end
as "Status"
from -- ...
The T-SQL case/when is a direct translation of if .. then return ... elif ... then return ... else return ... endif
Related
In my Employee table in SQL Server I have two datetime columns: HiringDate and ResignDate. I want to create a new column Status (Active, Inactive) in a view.
If HiringDate is NULL or greater than today = Inactive
If HiringDate is Active but ResignDate is earlier than today then Status also have to be Inactive.
Do I have to make some kind of nested case to make this work and I'm also wondering do I have to convert it to date format so the time portion are not included.
Would be very thankful for help.
Here is what ive tried so far but it doesnt work properly...
CASE
WHEN CONVERT(DATE,HiringDate) IS NOT NULL
OR CONVERT(DATE,HiringDate) <= CONVERT(DATE,GETDATE())
THEN
CASE
WHEN CONVERT(DATE,ISNULL(ResignDate, CONVERT(DATE,'2099-12-30'))) <= CONVERT(DATE,GETDATE())
THEN 'Active'
ELSE 'Inactive'
END
ELSE 'Inactive'
END as Status
Try this below combine logic in one CASE expression:
CASE
WHEN HiringDate IS NOT NULL
or HiringDate >= GETDATE()
or ResignDate >= GETDATE()
THEN 'Active'
ELSE 'Inactive'
END as Status
Can you please try with this below new logic-
CASE
WHEN (
CONVERT(DATE,HiringDate) IS NOT NULL
OR
CONVERT(DATE,HiringDate) <= CONVERT(DATE,GETDATE()
)
AND
CONVERT(DATE,ISNULL(ResignDate, CONVERT(DATE,'2099-12-30')))
<= CONVERT(DATE,GETDATE())
THEN 'Active'
ELSE 'Inactive'
END as EmployeeStatus
You can try below CASE logic.
CASE WHEN HiringDate IS NULL THEN 'InActive'
WHEN CAST(HiringDate AS DATE) > CAST(GETDATE() AS DATE) THEN 'InActive'
WHEN HiringDate IS NOT NULL AND CAST(ResignDate AS DATE) < CAST(GETDATE() AS DATE) THEN 'InActive'
ELSE 'Active'
END As Status
I have this query
SELECT mylearning.Employee_Id,
case
when max(case when not mylearning.CourseStatusTXT = 'Completed' then 1 else 0 end) = 0 then '2018 Complete'
when max(case when mylearning.CourseStatusTXT in ('Started', 'Not Started') then 1 else 0 end) = 1 then '2018 Not Complete'
end as Completion_Status
FROM Analytics.myLearning_Completions as mylearning inner join Analytics.Workday WD on mylearning.Employee_ID = WD.Employee_ID
And I want to add a condition to the first when statement to make it like this
when max(case when not mylearning.CourseStatusTXT = 'Completed' then 1 else 0 end) = 0
and WD.Adjusted_Hire_Date like '2019% '
and mylearning.CourseTimeCompletedH < cast (WD.Adjusted_Hire_Date as date format 'YYYY/MM/DD') +7
then '2018 Complete'
but I keep getting this error
Executed as Single statement. Failed [3504 : HY000] Selected non-aggregate values must be part of the associated group.
Elapsed time = 00:00:00.069
How can I fix it?
Like a couple others mentioned, you are trying to mix grouped data with non-aggregated data in your calculation, which is why you're getting the 3504 error. You need to either include the referenced columns in your GROUP BY or include them inside an aggregate function (i.e. MAX).
I'm not 100% sure if this is what you're after, but hopefully it can help you along.
SELECT
mylearning.Employee_Id,
CASE
WHEN
MAX(CASE WHEN NOT mylearning.CourseStatusTXT = 'Completed' THEN 1 ELSE 0 END) = 0 AND
WD.Adjusted_Hire_Date like '2019% ' AND
-- Check if most recently completed course is before Hire (Date + 1 week)
MAX(mylearning.CourseTimeCompletedH) <
CAST(WD.Adjusted_Hire_Date AS DATE FORMAT 'YYYY/MM/DD') + 7
THEN '2018 Complete' -- No incomplete learnings
WHEN MAX(
CASE WHEN mylearning.CourseStatusTXT IN ('Started', 'Not Started') THEN 1 ELSE 0 END
) = 1 THEN '2018 Not Complete' -- Started / Not Started learnings exist
END AS Completion_Status
FROM Analytics.myLearning_Completions as mylearning -- Get learning info
INNER JOIN Analytics.Workday WD on mylearning.Employee_ID = WD.Employee_ID -- Employee info
GROUP BY mylearning.Employee_Id, WD.Adjusted_Hire_Date
This will give you a summary per employee, with a couple assumptions:
Assuming employee_ID value in Analytics.Workday is a unique value (one-to-one join), to use WD.Adjusted_Hire_Date in your comparisons, you just need to include it in the GROUP BY.
Assuming you have multiple courses per employee_Id, in order to use mylearning.CourseTimeCompletedH in your comparisons, you'd need to wrap that in an aggregate like MAX.
The caveat here is that the query will check if the most recently completed course per employee is before the "hire_date" expression, so I'm not sure if that's what you're after.
Give it a try and let me know.
The issue here is that you are mixing detail row by row information in the same query as group or aggregated data. Aggregated data will output a single value for all the rows unless you have a group by clause. If you have a group by clause then it will output a single value for each group. When you are grouping you can also include any values that are in the group by clause since they will be unique for the group.
if you want this data for each employee, then you could group by employee_id. Any other data would need to also be an aggregate like Max(Adjusted_Hire_Date)
Maybe this is what you want?
SELECT
mylearning.employee_id
, case
when CourseStatusTXT = 'Completed' and WD.Adjusted_Hire_Date like '2019%'
and mylearning.CourseTimeCompletedH < cast (WD.Adjusted_Hire_Date as date format 'YYYY/MM/DD') +7
then '2018 Complete'
else '2018 Not Complete'
end CompletionStatus
FROM myLearning_Completions mylearning, Workday WD
WHERE mylearning.employee_id = WD.employee_id
I have a table FinalQuote in SQL Server with these columns:
Q_hub_from : Perth, Burnie, Sydney etc.
Q_hub_to : Perth, Burnie, Sydney etc.
FinalMargin : 400, 500, 650 etc.
processed_at : Date Time
BookedYN : Yes/No.
I want to create a SSRS report which will show the average value of FinalMargin for all the rows from a specific Q_hub_from to specific Q_hub_to. Also wanna show average margin in two columns: one contain average of rows where BookedYN is 'YES' and other contain average of rows where BookedYN is 'NO'. It is working fine and display required result when I specify a date range(for processed_at) in query.
My query so far is:
SELECT
Q_hub_from, Q_hub_to,
ROUND(AVG(FinalMargin), 0) AS Margin,
COUNT(*) AS NoOfQuotesDone,
COUNT(CASE BookedYN WHEN 'Yes' THEN 1 ELSE NULL END) AS NoOfQuotesBooked,
ROUND(AVG(CASE BookedYN WHEN 'No' THEN FinalMargin ELSE NULL END), 0) AS MarginWhenNotBooked,
ROUND(AVG(CASE BookedYN WHEN 'Yes' THEN FinalMargin ELSE NULL END), 0) AS MarginWhenBooked
FROM
FinalQuote
WHERE
Q_hub_from <> ''
AND Q_hub_from IS NOT NULL
--AND CAST(processed_at as date) BETWEEN '2018-08-01' AND '2018-10-10'
AND CAST(processed_at AS DATE) BETWEEN DATEADD(day, -10, GETDATE()) AND GETDATE()
GROUP BY
Q_hub_from, Q_hub_to
ORDER BY
Q_hub_from ASC
This query produces this output:
But I want date range to be selected by user, so I added StartDate and EndDate parameters. My processed_at column only mentioned in the WHERE clause, not in the select statement, so I get this error:
[rsMissingFieldInDataSet] and [rsErrorReadingDataSetField]
When I add processed_at field in DataSet and in GROUP BY clause then it is working (although still displays previous error) but now result is not expected. It shows 2 rows for same Q_hub_from and Q_hub_to.
Query:
SELECT Q_hub_from, Q_hub_to, processed_at, ROUND(AVG(FinalMargin),0) AS Margin,
COUNT(*) AS NoOfQuotesDone, COUNT(case BookedYN when 'Yes' then 1 else null end) AS NoOfQuotesBooked,
ROUND(AVG(case BookedYN when 'No' then FinalMargin else null end),0) AS MarginWhenNotBooked, ROUND(AVG(case BookedYN when 'Yes' then FinalMargin else null end),0) AS MarginWhenBooked
FROM FinalQuote
WHERE Q_hub_from <> '' AND Q_hub_from IS NOT NULL
AND processed_at between #StartDate AND #EndDate
GROUP BY Q_hub_from, Q_hub_to, processed_at
ORDER BY Q_hub_from ASC
Output:
If anyone can help me in achieving the required result that only show 1 row for same Q_hub_from to Q-hub_to within specific date range(i.e. processed_at between StartDate and EndDate) that will be of great help. I don't wanna display processed_at column. I know I am doing something wrong as Its my first time with SSRS.
Feel free to ask if you want to know more. Any help will be appreciated! Thanks.
If you have not set the values for parametes then try to assign some values to parameters and make sure parameter type is Date.
You can do it like this,
create a dataset and put this query select DATEADD(day, -10, GETDATE()) AS StartDate, GETDATE() AS EndDate
Use this dataset for your both the parameters only in default values section. Don't add it in available values section.
Suggestion 1: AND cast( processed_at as date) between #StartDate AND #EndDate . As you need to make sure how this column is stored in the tables. If it is DateTime then do an implicit cast to date.
Suggestion 2: on the SSRS make sure you can see your 2 params are params. IF you do then DO NOT SET any values for them. See if you can pick any random range and report renders.
Suggestion 3: if you have to put default values make sure they are either query or best case stored proc generated (sometime like usp_report_params_defaultDateRange). You will give this for default date range. Also type will be date and not int, varchar, etc.
Suggestion 4: If above fail trying building a query and just hardcoding the values so something like Select '2000-01-01' as Q_hub_from, '2001-01-01' as Q_hub_to from table name where cast( processed_at as date) between #StartDate AND #EndDate and see if it works. Add 1 column at a time and anchor to report and see if it gives you error. (NOTE YOU HAVE TO DELETE .DATA file from your local Bin folder after each local successful run)
My table is PRODUCTINFO:
Column name : product_name | launch_date
Sample Date : product1 2017-01-20
I need a SQL query to decide if the product is newly launched or not.
Business rule :
if (launch_date - currentdate < 0 && currentdate - launch_date < 90)
newly_launched = 'YES'
else
newly_launched = 'NO'
where currentdate is today's date.
SQL query I am witting is like :
SELECT launch_date, X as newly_launched
FROM PRODUCTINFO
WHERE product_name = 'product1'
I am not able to figure out correct replacement of 'X' in my query for desired result.
Problem I am facing is using currentdate and if else block in my query
Please help.
One way to get currentdate in DB2 using following query :
SELECT VARCHAR_FORMAT(CURRENT TIMESTAMP, 'YYYYMMDD')
FROM SYSIBM.SYSDUMMY1
Still not sure how to use this with my if else scenario.
Answer here don't solve my problem as this scenario is if-else based.
use TIMESTAMPDIFF with 16 as first parameter for count number days between 2 timestamps, for more detail look here
try this
select launch_date,
case when TIMESTAMPDIFF( 16, cast(cast(launch_date as timestamp) - current timestamp as char(22))) >0 and
TIMESTAMPDIFF( 16, cast(cast(launch_date as timestamp) - current timestamp as char(22))) <90 then 'YES' else 'NO' end newly
from PRODUCTINFO
WHERE product_name = 'product1'
simply use datediff function in a case syntax, I hope it could help!
SELECT launch_date,
case
when DATEDIFF(day,launch_date,getdate()) BETWEEN 0 AND 90 then 'YES'
else 'NO'
end AS newly_launched
FROM PRODUCTINFO
WHERE product_name = 'product1'
in case you want to do it for all your records:
SELECT launch_date,
case
when DATEDIFF(day,launch_date,getdate()) BETWEEN 0 AND 90 then 'YES'
else 'NO'
end AS newly_launched
FROM PRODUCTINFO
Table - Activity(jobid,duedate,status)
status can be either 'Complete' or "NotComplete".
I need a single sql query to get
how many jobs are complete
how many jobs are not-complete having duedate is greater than current date
how many jobs are not-complete having duedate is less than current date
Can anyone please help me with this? Result should have only 3 rows and two columns.
Edit : I am looking for best query, perhaps with any inbuilt function/keyword which performs task in single line query. Not sure if it is possible.
Something like this:
SELECT Count(jobid) AS total,
'Completed'
FROM activity
GROUP BY status
HAVING status = 'Complete'
UNION
SELECT Count(jobid) AS total,
'Completed Due in past.'
FROM activity
WHERE duedate >= Getdate()
GROUP BY status
HAVING status = 'Complete'
UNION
SELECT Count(jobid) AS total,
'Completed Due in past.'
FROM activity
WHERE duedate < Getdate()
GROUP BY status
HAVING status = 'Complete'
Try case :
select
case when status='Complete' then '1'
when status='NotComplete' and duedate >= getdate() then '2'
else '3' end,
count(jobid)
from Activity
group by
case when status='Complete' then '1'
when status='NotComplete' and duedate >= getdate() then '2'
else '3' end
Try This:-
SELECT COUNT(JOBID) Completed Jobs, STATUS
FROM Activity
WHERE STATUS = "Complete"
GROUP BY STATUS
UNION
SELECT COUNT(JOBID) Completed Jobs, STATUS
FROM Activity
WHERE duedate > GETDATE() AND STATUS = "NotComplete"
GROUP BY STATUS
UNION
SELECT COUNT(JOBID) Completed Jobs, STATUS
FROM Activity
WHERE duedate < GETDATE() AND STATUS = "NotComplete"
GROUP BY STATUS;
This might be helpful to you.
Select sum( case when status = 'Complete' then 1 else 0 end ) as completedJobs,
Sum ( case when status ='NotCompleted' and duedate > getdate() then 1 else 0 end ) as notcompletedinDuedate,
Sum ( case when status ='NotCompleted' and duedate < getdate() then 1 else 0 end ) as notcompletedJobs
From Activity
Everyone, Thanks for your reply. I was looking for best query with 2 columns. This is my solution. If anyone have short/good version query, please suggest.
;with cte as (
select
case
when stat = 'N' and duedate > GETDATE() then 'NG'
when stat = 'N' and duedate < GETDATE() then 'NL'
else stat
end As S, duedate from activity)
select S,COUNT(*) from CTE group by (S)