SQLite: Select row based on time of day? - sqlite

I have a SQLite table like the following:
+-----------+-------+
| StartTime | Name |
+-----------+-------+
| 08:00:00 | zone1 |
| 13:00:00 | zone2 |
| 17:30:00 | zone3 |
| 22:00:00 | zone4 |
+-----------+-------+
I'm trying to write a query that will return the row based on the current time:
If CurrentTime is 08:30 it will return zone1
If CurrentTime is 16:40 it will return zone2
If Currenttime is 04:01 it will return zone4
and so on...
So far I had some luck but not exactly what I wanted
SELECT * FROM table WHERE StartTime >= time('now', 'localtime')
ORDER BY StartTime LIMIT 1;
I've tried some variations of the above statement, but none returns the result I'm after.
Thanks!

You'll make your life a lot easier if you add an "EndTime" field as well, as you can then simply check if the current time is within the start and end time.
For example, if your database table consisted of the following...
+-----------+----------+-------+
| StartTime | EndTime | Name |
+-----------+----------+-------+
| 08:00:00 | 12:59:59 | zone1 |
| 13:00:00 | 17:29:59 | zone2 |
| 17:30:00 | 21:59:59 | zone3 |
| 22:00:00 | 07:59:59 | zone4 |
+-----------+----------+-------+
...you could simply use a query along the lines of:
SELECT Name FROM table WHERE StartTime >= time('now', 'localtime')
AND EndTime <= time('now', 'localtime')
ORDER BY StartTime LIMIT 1;

Have you tried a having clause?
SELECT * FROM table WHERE StartTime >= time('now', 'localtime')
HAVING StartTime = MIN(StartTime)

Two versions.
This is the easiest to understand, but it assumes that max(Name) is meaningful. That is, it assumes that the values in "Name" are ordered from low to high.
SELECT max(Name)
FROM yourtable
WHERE StartTime< time("16:40:00");
This version uses a scalar subquery. It doesn't depend on any meaningful order to the names. I'd consider this version to be more robust.
SELECT Name
FROM yourtable
WHERE StartTime = (SELECT max(StartTime)
FROM yourtable
WHERE StartTime < time("16:40:00")
);
You'll want to replace the time()
literals with
time('now','localtime') in
production.
Expect an empty set if you run any of
these queries before 08:00 local
time.

Related

Make partitions based on difference in date in Postgres window function

I have data in the following format
id | first_name | last_name | birth_date
abc | Jared | Pollard | 1970-01-01
def | Jared | Pollard | 1972-02-02
ghi | Jared | Pollard | 1980-01-01
klm | Jared | Pollard | 2015-01-01
and I would like a query which groups data based on the following rule
If first_name, last_name are equal and birth_dates are within 5 years of each other, than records belong to same group
So the above data contains three groups group1=(abc, def), group2=(ghi) and group3=(klm)
Currently I have the following query which incorrectly creates only 2 groups, group1=(abc, def) and group2=(ghi, klm)
SELECT
g.id,
FIRST_VALUE(g.id) OVER (PARTITION BY lower(trim(g.last_name)), lower(trim(g.first_name)),
CASE WHEN g.birth_date between g.fv_birth_date - interval '5 year' AND g.fv_birth_date + interval '5 year' THEN 1 ELSE 0 END
ORDER BY g.last_used_dt DESC NULLS LAST) AS cluster_id
FROM (
SELECT id, last_used_dt, last_name, first_name, birth_date,
FIRST_VALUE(birth_date)
OVER (PARTITION BY
lower(trim(last_name)),
lower(trim(first_name))
ORDER BY last_used_dt DESC NULLS LAST) AS fv_birth_date
FROM guest
) g;
I understand this is because of the CASE statement within the PARTITION BY clause but am unable to come up with any other query

ms access: give a date in a table how do I create a from_date and to_date field in a query

MS Access. I'm querying a table that displays a client_name, release_name, release_date for a number of clients and releases. I'm trying to write a query that returns the following data for one client: client_name, release_name, from_release_date, to_release_date. In this case the from_release_date is the original release_date from the underlying table but the new field in the query to_release_date is the day before the next release was installed. For example:
+-------------+-----------+-------------------+-------------------+
| client_name | release | from_release_date | to_release date |
+-------------+-----------+-------------------+-------------------+
| client A | release 1 | 01/01/2017 | 01/02/2017 |
| client A | release 2 | 02/02/2017 | 02/03/2017 |
| client A | release 3 | 03/03/2017 | |
+-------------+-----------+-------------------+-------------------+
How do I create this 'to_release_date' field?
Use a subquery:
Select
client_name,
release_name,
release_date As from_release_date,
(Select Top 1
DateAdd("d", -1, T.release_date)
From
YourTable As T
Where
T.client_name = YourTable.client_name
And
T.release_date > YourTable.release_date
Order By
T.release_date Desc) As to_release_date
From
YourTable

Add value from row to date in SELECT query

Assume I have the following SQLite table "foobar":
id | start | duration
---+------------+---------
1 | 2016-05-12 | 2
2 | 2016-01-01 | 5
My goal is to get the sum of the start-date and the duration (durations are in years).
So my desired result is the following:
id | end
---+-----------
1 | 2018-05-12
2 | 2021-01-01
Is this possible with a single query?
I know it is possible to add static values as follows
SELECT date(start, "+2 years") FROM foobar;
but I could not find a way to replace the static 2 with the dynamic value of duration.
SELECT date(start, "+" || duration || " years")
FROM foobar;
SQLFiddle demo

Generating attendance list for hours without a matching row

I have a project that calculates work hour from the attendance logs that I import from attendance machine. I use SQLite database and VB .NET.
First I'll show the table that I use:
CREATE TABLE [CheckLogs] (
[IDCheckLog] INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
[IDEmployee] TEXT NOT NULL,
[Dates] TEXT NOT NULL,
[In] TEXT,
[Out] TEXT,
[OverTime] NUMERIC DEFAULT 0);
CREATE TABLE integers (i INTEGER NOT NULL PRIMARY KEY);
INSERT INTO integers (i) VALUES
(0),(1),(2),(3),(4),(5),(6),(7),(8),(9);
Table CheckLogs is the data that I import from the attendance machine. The OverTime column is calculated in my program. Table integer is used to create the date list, I got it from here.
I want to generate a view that shows employee attendance between 2 dates and display the CheckLogs data if the employee is present and null if absent. Because in the table CheckLogs, when the employee is absent then there is no data from that day from this employee.
This is the view that I desired (this is report for employee 10001 between 2014-10-01 and 2014-10-05):
Dates | IDEmployee | In | Out
---------------------------------------
2014-10-01 | 10001 | 07:00 | 16:00
2014-10-02 | 10001 | 07:01 | 15:58
2014-10-03 | 10001 | null | null
2014-10-04 | 10001 | 07:08 | 15:48
2014-10-05 | 10001 | null | null
And this is the query that I have now:
SELECT X.[Dates], C.[IDEmployee], C.[In], C.[Out]
FROM
(select date('2014-10-01', '+' || (H.i*100 + T.i*10 + U.i) || ' day') as Dates
from integers as H
cross
join integers as T
cross
join integers as U
where date('2005-01-25', '+' || (H.i*100 + T.i*10 + U.i) || ' day') <= '2014-10-05') AS X
, CheckLogs AS C USING (Dates)
WHERE C.[IDEmployee]='10001'
From this query I have this result:
Dates | IDEmployee | In | Out
---------------------------------------
2014-10-01 | 10001 | 07:00 | 16:00
2014-10-02 | 10001 | 07:01 | 15:58
2014-10-04 | 10001 | 07:08 | 15:48
To get NULL values for rows without a match, you need an outer join.
And you have to take care not to filter out those rows with a WHERE clause that would not match NULL values; to get dates that do not match a condition, you have to put that condition into the join's ON clause:
SELECT ...
FROM ( ... ) AS X
LEFT JOIN CheckLogs AS C ON C.Dates = X.Dates AND
C.IDEmployee = '10001'

Pull a row from SQL database based on if the value of a column is changed

I need to pull a row in a select statement from a SQL database if a certain value in a table is changed.
For example, I have a column called price in a Price table. If the user changes the value for price (through an asp.net app), I want to select that entire row. This is going to be done in a workflow and an email is sent to the user that the row that was changed AFTER it was changed.
Does this make sense? Can someone point me in the right direction of a procedure or function to use? Thanks.
You could use an SQL trigger to accomplish this.
There is a tutorial (using Price as you described) that shows how to accomplish this here: http://benreichelt.net/blog/2005/12/13/making-a-trigger-fire-on-column-change/
well, in order to update a row, you'll have to update that row "WHERE uniqueID = [someid]". Can't you simply run a select immediately after that? (SELECT * FROM [table] WHERE uniquueID = [someid])
Without knowing what your data looks like (or what database this is, it's a little difficult) but assuming you have a history table with a date and an ID that stays the same like this...
+----+-------+------------+
| ID | PRICE | CHNG_DATE |
+----+-------+------------+
| 1 | 2.5 | 2001-01-01 |
| 1 | 42 | 2001-01-01 |
| 2 | 4 | 2001-01-01 |
| 2 | 4 | 2001-01-01 |
| 3 | 4 | 2001-01-01 |
| 3 | 3 | 2001-01-01 |
| 3 | 2 | 2001-01-01 |
+----+-------+------------+
and your database supports With and Row_number You could write the following
WITH data
AS (SELECT id,
price,
chng_date,
Row_number()
OVER (
partition BY id
ORDER BY chng_date) rn
FROM price)
SELECT data.id,
data.price new,
data_prv.price old,
data.chng_date
FROM data
INNER JOIN data data_prv
ON data.id = data_prv.id
AND data.rn = data_prv.rn + 1
WHERE data.price <> data_prv.price
That would produce this
+----+-----+-----+------------+
| ID | NEW | OLD | CHNG_DATE |
+----+-----+-----+------------+
| 1 | 42 | 2.5 | 2001-01-01 |
| 3 | 3 | 4 | 2001-01-01 |
| 3 | 2 | 3 | 2001-01-01 |
+----+-----+-----+------------+
Demo
If your Database supports LAG() its even eaiser
WITH data
AS (SELECT id,
price new,
chng_date,
Lag(price)
OVER (
partition BY id
ORDER BY chng_date) old
FROM price)
SELECT id,
new,
old,
chng_date
FROM data
WHERE new <> old
Demo

Resources