MySQL: Calculated Column Based on Date Range - mysql

How does one create a calculated column that yields the value of 1 if a date falls within 2015, else 0?
I spent yesterday googling, and searching StackOverflow, for solutions to no avail. From what I learned about CASE WHEN, BETWEEN, and CAST, I put together the below SQL script.
However, the below (truncated) script yields all 0's, despite having corresponding Prescreen dates in 2015, 2016, and even dates of 0000-00-00, as follows:
SELECT
table_r.R_Number,
table_c.ref_num,
DATE(STR_TO_DATE(table_c.Prescreen, '%d-%b-%y')) AS Prescreen,
CASE
WHEN Prescreen BETWEEN CAST('2015-01-01' AS DATE) AND CAST('2015-12-31' AS DATE) THEN 1
ELSE 0
END AS YTD2015_Prescreen,
table_r.Region,
FROM
table_c
INNER JOIN
table_r ON table_c.R_Number = table_r.R_Number
WHERE
table_c.Int <> ''
;
I humbly ask you to lend me your genius. Thank you. :)

Try this:
SELECT
table_r.R_Number,
table_c.ref_num,
STR_TO_DATE(table_c.Prescreen,'%d-%b-%y') AS Prescreen,
CASE
WHEN STR_TO_DATE(table_c.Prescreen,'%d-%b-%y') BETWEEN CAST('20150101'AS DATE) AND CAST('20151231' AS DATE) THEN 1
ELSE 0
END AS YTD2015_Prescreen,
table_r.Region,
FROM
table_c
INNER JOIN
table_r ON table_c.R_Number = table_r.R_Number
WHERE
table_c.Int <> ''
;

Related

Generating complex sql tables

I currently have an employee logging sql table that has 3 columns
fromState: String,
toState: String,
timestamp: DateTime
fromState is either In or Out. In means employee came in and Out means employee went out. Each row can only transition from In to Out or Out to In.
I'd like to generate a temporary table in sql to keep track during a given hour (hour by hour), how many employees are there in the company. Aka, resulting table has columns HourBucket, NumEmployees.
In non-SQL code I can do this by initializing the numEmployees as 0 and go through the table row by row (sorted by timestamp) and add (employee came in) or subtract (went out) to numEmployees (bucketed by timestamp hour).
I'm clueless as how to do this in SQL. Any clues?
Use a COUNT ... GROUP BY query. Can't see what you're using toState from your description though! Also, assuming you have an employeeID field.
E.g.
SELECT fromState AS 'Status', COUNT(*) AS 'Number'
FROM StaffinBuildingTable
INNER JOIN (SELECT employeeID AS 'empID', MAX(timestamp) AS 'latest' FROM StaffinBuildingTable GROUP BY employeeID) AS LastEntry ON StaffinBuildingTable.employeeID = LastEntry.empID
GROUP BY fromState
The LastEntry subquery will produce a list of employeeIDs limited to the last timestamp for each employee.
The INNER JOIN will limit the main table to just the employeeIDs that match both sides.
The outer GROUP BY produces the count.
SELECT HOUR(SBT.timestamp) AS 'Hour', SBT.fromState AS 'Status', COUNT(*) AS 'Number'
FROM StaffinBuildingTable AS SBT
INNER JOIN (
SELECT SBIJ.employeeID AS 'empID', MAX(timestamp) AS 'latest'
FROM StaffinBuildingTable AS SBIJ
WHERE DATE(SBIJ.timestamp) = CURDATE()
GROUP BY SBIJ.employeeID) AS LastEntry ON SBT.employeeID = LastEntry.empID
GROUP BY SBT.fromState, HOUR(SBT.timestamp)
Replace CURDATE() with whatever date you are interested in.
Note this is non-optimal as it calculates the HOUR twice - once for the data and once for the group.
Again you are using the INNER JOIN to limit the number of returned row, this time to the last timestamp on a given day.
To me your description of the FromState and ToState seem the wrong way round, I'd expect to doing this based on the ToState. But assuming I'm wrong on that the following should point you in the right direction:
First, I create a "Numbers" table containing 24 rows one for each hour of the day:
create table tblHours
(Number int);
insert into tblHours values
(0),(1),(2),(3),(4),(5),(6),(7),
(8),(9),(10),(11),(12),(13),(14),(15),
(16),(17),(18),(19),(20),(21),(22),(23);
Then for each date in your employee logging table, I create a row in another new table to contain your counts:
create table tblDailyHours
(
HourBucket datetime,
NumEmployees int
);
insert into tblDailyHours (HourBucket, NumEmployees)
select distinct
date_add(date(t.timeStamp), interval h.Number HOUR) as HourBucket,
0 as NumEmployees
from
tblEmployeeLogging t
CROSS JOIN tblHours h;
Then I update this table to contain all the relevant counts:
update tblDailyHours h
join
(select
h2.HourBucket,
sum(case when el.fromState = 'In' then 1 else -1 end) as cnt
from
tblDailyHours h2
join tblEmployeeLogging el on
h2.HourBucket >= el.timeStamp
group by h2.HourBucket
) cnt ON
h.HourBucket = cnt.HourBucket
set NumEmployees = cnt.cnt;
You can now retrieve the counts with
select *
from tblDailyHours
order by HourBucket;
The counts give the number on site at each of the times displayed, if you want during the hour in question, we'd need to tweak this a little.
There is a working version of this code (using not very realistic data in the logging table) here: rextester.com/DYOR23344
Original Answer (Based on a single over all count)
If you're happy to search over all rows, and want the current "head count" you can use this:
select
sum(case when t.FromState = 'In' then 1 else -1) as Heads
from
MyTable t
But if you know that there will always be no-one there at midnight, you can add a where clause to prevent it looking at more rows than it needs to:
where
date(t.timestamp) = curdate()
Again, on the assumption that the head count reaches zero at midnight, you can generalise that method to get a headcount at any time as follows:
where
date(t.timestamp) = "CENSUS DATE" AND
t.timestamp <= "CENSUS DATETIME"
Obviously you'd need to replace my quoted strings with code which returned the date and datetime of interest. If the headcount doesn't return to zero at midnight, you can achieve the same by removing the first line of the where clause.

BLANK VALUE IN SSRS BUT DATA IN SQL QUERY

I'm working in a solution in SSRS that it's driving me crazy, I will explain it a bit before shows you my problem:
Select 25 data values from a table with analog input data (from current, voltage, pressure, etc. tags) using parameters #startDate = yeterday 6am and #EndDate = today 6am. Now we have a table with 25 values from 6am to 6am from different tagID's.
My problem starts when just one tagId of 16, it's showing me in the SSRS presentation values 0.0000 when in the Sql output shows me -0.00548...
For practical purpouses I will just use 2 tagIds (MSF_PDI_003, MSF_PDI_004)
Here the SQL Query:
declare #startDate datetime2 = '2017-04-19 11:00',
#endDate datetime2 = '2017-04-20 11:00';
SELECT InstaTime,
MSF_PDI_003,
MSF_PDI_004
FROM (
SELECT
DATEADD(HH,-5,H.time) AS InstaTime,
SUM(
CASE
WHEN t.tagName = 'analog.MSF_PDI_003.curval'
Then H.value
ELSE 0
END) as MSF_PDI_003,
SUM(
CASE
WHEN t.tagName = 'analog.MSF_PDI_004.curval'
Then H.value
ELSE 0
END) as MSF_PDI_004
FROM hour H
INNER JOIN tag T
ON T.tagId = H.tagId
WHERE T.tagName IN
('analog.MSF_PDI_003.curval', 'analog.MSF_PDI_004.curval')
AND H.time >= #startDate
And H.time <= #endDate
GROUP BY time
) QueryData
order by InstaTime desc
And this the result of the query:
SQL QUERY RESULT IN SQL-SERVER
And these are the expressions that I'm using in the textboxes of the tablix in the SSRS (I used a test dataset for this query: summary_prueba)
=Fields!InstaTime.Value
=Fields!MSF_PDI_003.Value
=Fields!MSF_PDI_004.Value
And here the results of the table in SSRS:
CLICK IMAGE: SAMPLE2 SRSS
What could be the problem around here?
* Is the Only one with negative values, could be forcing a round? Something about a different format I should use?
Driving me nuts and can't find what's wrong. I tried to change the format and is the same, can you guys please help me? Because this thing doesn't let me sleep at night, I'm starting to have nightmares lol.
I'm using SQL Server 2012, and for the report MS Visual Studio Shell 2010.
Let's start by consolidating your query into one statement, instead of the UNION and separate SELECT SUM(...) that you have now:
declare #startDate datetime2 = '2017-04-18 11:00',
#endDate datetime2 = '2017-04-19 11:00';
SELECT InstaTime,
MSF_PDI_003,
MSF_PDI_004
FROM (
SELECT
DATEADD(HH,-5,H.time) AS InstaTime,
SUM(
CASE
WHEN t.tagName = 'analog.MSF_PDI_003.curval'
Then H.value
ELSE 0
END) as MSF_PDI_003,
SUM(
CASE
WHEN t.tagName = 'analog.MSF_PDI_004.curval'
Then H.value
ELSE 0
END) as MSF_PDI_004
FROM hour H
INNER JOIN tag T
ON T.tagId = H.tagId
WHERE T.tagName IN
('analog.MSF_PDI_003.curval', 'analog.MSF_PDI_004.curval')
AND H.time >= #startDate
And H.time <= #endDate
GROUP BY InstaTime
) QueryData
order by InstaTime desc
Now, if there is no matching 004 or 003 value, they will report as zero instead of being blank. Try this, and see whether this matches what you need.
All right I found a solution but not the problem, because I still don't understand why if in the sql server I can see data and in the QueryDesigner of SSRS I still have 0.00 values.
This is a relational DB, I use 2 tables, from the same database
DB: Timeseries
Table1: hour, from here I use value,time,tagId
Table2: tag, from here I use tagName,tagId
Both have tagId in common, but I just realized that exaclty just this signal MSF_PDI_004 it's not related to the tagName in the table tag.(Have to be an error when created that signal)
I changed the Query and instead of use the tagName I used the tagId, and everything was fine, I could see the same values in SSRS than I was seeing in the SQL SERVER.
Still I think its strange, because if the query works on SQL SERVER, why should not be transparent for the SSRS?
I hope somebody can explain me this, thank you for the ones who took time for read and help.

Count consecutive row occurrences

I have a MySQL table with three columns: takenOn (datetime - primary key), sleepDay (date), and type (int). This table contains my sleep data from when I go to bed to when I get up (at a minute interval).
As an example, if I go to bed on Oct 29th at 11:00pm and get up on Oct 30th at 6:00am, I will have 420 records (7 hours * 60 minutes). takenOn will range from 2016-10-29 23:00:00 to 2016-10-30 06:00:00. sleepDay will be 2016-10-30 for all 420 records. type is the "quality" of my sleep (1=asleep, 2=restless, 3=awake). I'm trying to get how many times I was restless/awake, which can be calculated by counting how many times I see type=2 (or type=3) consecutively.
So far, I have to following query, which works for one day only. Is this the correct/"efficient" way of doing this (as this method requires that I have the data without any "gaps" in takenOn)? Also, how can I expand it to calculate for all possible sleepDays?
SELECT
sleepDay,
SUM(CASE WHEN type = 2 THEN 1 ELSE 0 END) AS TimesRestless,
SUM(CASE WHEN type = 3 THEN 1 ELSE 0 END) AS TimesAwake
FROM
(SELECT s1.sleepDay, s1.type
FROM sleep s1
LEFT JOIN sleep s2
ON s2.takenOn = ADDTIME(s1.takenOn, '00:01:00')
WHERE
(s2.type <> s1.type OR s2.takenOn IS NULL)
AND s1.sleepDay = '2016-10-30'
ORDER BY s1.takenOn) a
I have created an SQL Fiddle - http://sqlfiddle.com/#!9/b33b4/3
Thank you!
Your own solution is quite alright, given the assumptions you are aware of.
I present here an alternative solution, that will deal well with gaps in the series, and can be used for more than one day at a time.
The downside is that it relies more heavily on non-standard MySql features (inline use of variables):
select sleepDay,
sum(type = 2) TimesRestless,
sum(type = 3) TimesAwake
from (
select #lagDay as lagDay,
#lagType as lagType,
#lagDay := sleepDay as sleepDay,
#lagType := type as type
from (select * from sleep order by takenOn) s1,
(select #lagDay := '',
#lagType := '') init
) s2
where lagDay <> sleepDay
or lagType <> type
group by sleepDay
To see how it works it can help to select the second select statement on its own. The inner-most select must have the order by clause to make sure the middle query will process the records in that order, which is important for the variable assignments that happen there.
See your updated SQL fiddle.

DATEDIFF SQL Query

I am at the final stage of my project and have the problem to find if a job is overdue. I link this to priority for example if a job has a priority of 1 it must be complete in 1 day, a priority of 4 then 4 days.
I have come up with a CASE however this doesn't seem to work any help would be appreciated.
SELECT `defect_Id`,`Overtasked`
WHERE
CASE DATEDIFF(DD,`date_Investigaton` - `CURRENT_DATE()`) >= `priority` AS Overtasked
THEN `Overtasked` == 'YES'
ELSE `Overtasked` == 'NO'
END
Solution
`SELECT defect_Id,
CASE WHEN DATEDIFF(date_Investigated, CURDATE()) >= priority
THEN 'YES'
ELSE 'NO'
END AS Overtasked
FROM defect_report
WHERE defect_Id = '82'`
Appreciate the guidance you guys give!
You are completely mixing up SQL dialects and even there are syntax errors.
Assuming you are talking about MS SQL Server let's try this:
SELECT defect_Id,
CASE WHEN DATEDIFF(DD, date_Investigaton, getdate()) >= priority
THEN 'YES'
ELSE 'NO'
END AS Overtasked
FROM <YourTable>
WHERE <YourWhereIfAny>
If date_Investigation is a DATE column, the subtraction date_Investigation - CURRENT_DATE() produces the number of days you need.
Otherwise (if it is a DATETIME, for example) both operands are converted to float and the result is something you are totally not expecting. For such situations use the DATEDIFF() function. It interprets its arguments as DATE (ignores the time part) and returns the integer number of days between the two dates.
Your query should be like:
SELECT
`defect_Id`,
IF (DATEDIFF(`date_Investigaton`, CURRENT_DATE()) >= `priority`, 'YES', 'NO')
AS `Overtasked`
FROM [...your table name here...]
WHERE [...conditions...]
Replace the parts in square brackets ([...]) with the name of the table where to get the data from and some conditions to limit the number of returned rows (otherwise it will get the entire table which, most probably, is not what you want).
Btw, CURRENT_DATE() is also a function. If you write it in backquotes (``), MySQL will try to find a column with this name and it will fail.
Read the accepted answer for this question. It explains when to use back ticks, single quotes or double quotes in MySQL (and partially in PHP).

MySQL Join, Select, multiple conditions

I am really stuck at this this multiple condition queries.
There are 2 sets of sample data:
Here's What I want:
I want to know the students that been honorable mentioned by times, ie n=1, n=2, n=3 ... What is their average amount received in 2012 per price, per month, per different type of rewards, and return NULL if there's no value in a particular Month.
So far I have
SELECT Type_Of_Reward, Honorable_Mention, MONTH(date)
FROM Data_2 LEFT JOIN
SELECT(Honorable_Mention, COUNT(*) FROM Data_2 GROUP BY Honorable_Mention ON Student_ID = Honorable_Mention)
WHERE YEAR(Data_1.date)=2012 AND...
Any comments/helps would be greatly appreciated.
You can try this one by using join and using case for all months make sure you have set proper datatype for date column if you are using any server side language i recommend you to make this type of data representation by using server side language for now you can try this
SELECT d.Type_Of_Reward, d2.Honorable_Mention,
(CASE WHEN d2.`Honorable_Mention` IS NOT NULL AND MONTH(d.`date`)=1 THEN d2.`Honorable_Mention` ELSE 0 END) AS jan,
. //for other months
.
.
.
(CASE WHEN d2.`Honorable_Mention_id` IS NOT NULL AND MONTH(d.`date`)=10 THEN d2.`Honorable_Mention` ELSE 0 END) AS `oct`
FROM
`data_1` d LEFT JOIN `data_2` d2 ON(d.`id`=d2 .`Honorable_Mention`)
MONTH