SQL search full time or partial time - sql

I am trying to create a stored procedure that can filter on a full or partial time. It should only filter on hours or minutes (not seconds) or both hours and minutes.
Using the sample data below:
#StartTimeFilter = '09:15' --> should return record #1
#StartTimeFilter = '10' --> should return records 2, 3, 10
#StartTimeFilter = '5' --> should return records 1, 2, 5, 6, 7, 8, 9
#StartTimeFilter = '45' --> should return records 5, 6
#StartTimeFilter = '13:45' --> should return record #6
#StartTimeFilter = '11:' --> should return records 4, 5
Code:
CREATE TABLE test
(
id INT,
startTime DateTime
);
INSERT INTO test (id, startTime) VALUES (1, '2021-10-25 09:15:00');
INSERT INTO test (id, startTime) VALUES (2, '2021-10-25 10:15:00');
INSERT INTO test (id, startTime) VALUES (3, '2021-10-25 10:30:00');
INSERT INTO test (id, startTime) VALUES (4, '2021-10-25 11:30:00');
INSERT INTO test (id, startTime) VALUES (5, '2021-10-25 11:45:00');
INSERT INTO test (id, startTime) VALUES (6, '2021-10-25 13:45:00');
INSERT INTO test (id, startTime) VALUES (7, '2021-10-25 14:50:00');
INSERT INTO test (id, startTime) VALUES (8, '2021-10-25 15:51:00');
INSERT INTO test (id, startTime) VALUES (9, '2021-10-25 15:58:00');
INSERT INTO test (id, startTime) VALUES (10,'2021-10-25 16:10:00');

It looks like you need a simple like string comparision:
declare #StartTimeFilter varchar(10)='5'
select *
from test
where Convert(varchar(5),starttime,114) like Concat('%',#StartTimeFilter,'%')

Related

SQL Timeline Query

read already some post but was not able to find a solution yet.
I gota table which looks like this:
and I would like to transform this data, so that I got a line (or row) per ID and an entry per date which displays the Status. The value column does not change its value for the corresponding id.
or
I am currently not able to do it. Even without the value row/line.
CREATE TABLE test (
id INT,
date1 text,
status1 INT,
value1 INT
);
INSERT INTO test VALUES (1, '01.01.2022', 1, 60);
INSERT INTO test VALUES (2, '01.01.2022', 1, 30);
INSERT INTO test VALUES (3, '01.01.2022', 7, 90);
INSERT INTO test VALUES (1, '02.01.2022', 7, 60);
INSERT INTO test VALUES (2, '02.01.2022', 7, 30);
INSERT INTO test VALUES (3, '02.01.2022', 3, 90);
INSERT INTO test VALUES (1, '03.01.2022', 7, 60);
INSERT INTO test VALUES (2, '03.01.2022', 5, 30);
INSERT INTO test VALUES (3, '03.01.2022', 7, 90);
Based on your suggestions I tried:
SELECT *
FROM
(
SELECT id, value1
FROM test
) AS SourceTable
PIVOT(AVG(status1) FOR date1 IN(select DISTINCT date1
from test)) AS PivotTable;
But I can not find my error.
Schema (MySQL v8.0)
CREATE TABLE test (
id INT,
date text,
status INT,
value INT
);
INSERT INTO test VALUES (1, '01.01.2022', 1, 60);
INSERT INTO test VALUES (2, '01.01.2022', 1, 30);
INSERT INTO test VALUES (3, '01.01.2022', 7, 90);
INSERT INTO test VALUES (1, '02.01.2022', 7, 60);
INSERT INTO test VALUES (2, '02.01.2022', 7, 30);
INSERT INTO test VALUES (3, '02.01.2022', 3, 90);
INSERT INTO test VALUES (1, '03.01.2022', 7, 60);
INSERT INTO test VALUES (2, '03.01.2022', 5, 30);
INSERT INTO test VALUES (3, '03.01.2022', 7, 90);
Query #1
SELECT
ID,
MAX(VALUE) AS VALUE,
sum(CASE WHEN date = '01.01.2022' THEN status ELSE 0 END) AS '01.01.2022',
sum(CASE WHEN date = '02.01.2022' THEN status ELSE 0 END) AS '02.01.2022',
sum(CASE WHEN date = '03.01.2022' THEN status ELSE 0 END) AS '03.01.2022'
FROM test
GROUP BY ID;
ID
VALUE
01.01.2022
02.01.2022
03.01.2022
1
60
1
7
7
2
30
1
7
5
3
90
7
3
7
View on DB Fiddle

Find the total time taken by each `id` within a 1 hours

How to find the total time taken by each id.
There must be one activity within an hour (After the start of the one activity),
and if there is any activity before the 1hrs time is elapsed, consider that time in the previous slot, calculate the time differences.
if 1 hrs has already passed now check if there is any other activity within a 1hrs period
Sample data is:
create table test (
id integer not null,
ts datetime not null
);
insert into test values (1, '2012-01-01 08:00');
insert into test values (1, '2012-01-01 08:01');
insert into test values (1, '2012-01-01 08:06');
insert into test values (1, '2012-01-01 08:30');
insert into test values (1, '2012-01-01 09:35');
insert into test values (1, '2012-01-02 16:10');
insert into test values (1, '2012-01-02 16:20');
insert into test values (1, '2012-01-03 06:40');
insert into test values (1, '2012-01-03 06:41');
insert into test values (2, '2012-01-01 08:30');
insert into test values (2, '2012-01-01 09:26');
insert into test values (2, '2012-01-01 10:25');
The output column will be:
insert into test values (1, '2012-01-01 08:00');
insert into test values (1, '2012-01-01 08:01');
insert into test values (1, '2012-01-01 08:06');
insert into test values (1, '2012-01-01 08:30');
Here the differences are exactly: 00:30:00
and there is the record which but it is after 1 hr, so we didn't add this activity on the previous slot and there is no activity up to 1 hour from this time so we do not consider this activity
insert into test values (1, '2012-01-01 09:35');`
Now, this runs for: 00:10:00
insert into test values (1, '2012-01-02 16:10');
insert into test values (1, '2012-01-02 16:20');
Similarly, this runs for 00:01:00
insert into test values (1, '2012-01-03 06:40');
insert into test values (1, '2012-01-03 06:41');
So the total time for id=1 will be 00:41:00.
id | Time duration (hh:mm:ss)
1 | 00:41:00
2 | 01:55:00
I couldn't think of how to start with this problem, any possible head-start would be appreciated. Thank you!
Your rules are a bit hard to follow, but I think I understand them. Count the gap between two rows for the same id if the second is less than an hour after the first. Then aggregate by the id.
So:
select id, sum(datediff(minute, ts, next_ts)) as duration_minutes
from (select t.*,
lead(ts) over (partition by id order by ts) as next_ts
from test t
) t
where datediff(minute, ts, next_ts) < 60
group by id;
Here is a db<>fiddle.
I am reluctant to convert the duration to a time value, because that is limited to just 24 hours.

Sample observations per group without replacement in SQL

Using the provided table I would like to sample let's say 2 users per day so that users assigned to the two days are different. Of course the problem I have is more sophisticated, but this simple example gives the idea.
drop table if exists test;
create table test (
user_id int,
day_of_week int);
insert into test values (1, 1);
insert into test values (1, 2);
insert into test values (2, 1);
insert into test values (2, 2);
insert into test values (3, 1);
insert into test values (3, 2);
insert into test values (4, 1);
insert into test values (4, 2);
insert into test values (5, 1);
insert into test values (5, 2);
insert into test values (6, 1);
insert into test values (6, 2);
The expected results would look like this:
create table results (
user_id int,
day_of_week int);
insert into results values (1, 1);
insert into results values (2, 1);
insert into results values (3, 2);
insert into results values (6, 2);
You can use window functions. Here is an example . . . although the details do depend on your database (functions for random numbers vary by database):
select t.*
from (select t.*, row_number() over (partition by day_of_week order by random()) as seqnum
from test t
) t
where seqnum <= 2;

How to insert multiple row values into SQL

I have the following 3 tables:
CREATE TABLE Tests (
Test_ID INT,
TestName VARCHAR(50));
INSERT INTO Tests VALUES (1, 'SQL Test');
INSERT INTO Tests VALUES (2, 'C# Test');
INSERT INTO Tests VALUES (3, 'Java Test');
CREATE TABLE Users (
[User_ID] INT,
UserName VARCHAR(50));
INSERT INTO Users VALUES (1, 'Joe');
INSERT INTO Users VALUES (2, 'Jack');
INSERT INTO Users VALUES (3, 'Jane');
CREATE TABLE UserTests (
ID INT,
[User_ID] INT,
Test_ID INT,
Completed INT);
INSERT INTO UserTests VALUES (1, 1, 1, 0);
INSERT INTO UserTests VALUES (2, 1, 2, 1);
INSERT INTO UserTests VALUES (3, 1, 3, 1);
INSERT INTO UserTests VALUES (4, 2, 1, 0);
INSERT INTO UserTests VALUES (5, 2, 2, 0);
INSERT INTO UserTests VALUES (6, 2, 3, 0);
INSERT INTO UserTests VALUES (7, 3, 1, 1);
INSERT INTO UserTests VALUES (8, 3, 2, 1);
INSERT INTO UserTests VALUES (9, 3, 3, 1);
I would like to create some rule/trigger so that when a new user gets added to the Users table, an entry for each Test and that user's Id will get added to the UserTests table.
Something like this if the new user ID is 5:
INSERT dbo.UserTest
(USER_ID, TEST_ID, Completed)
VALUES
(5, SELECT TEST_ID FROM Tests, 0)
That syntax is of course wrong but to give an idea of what I expect to happen.
So I expect that statement to add these values to the UserTests table:
User ID| Test ID| Completed
5 | 1 | 0
5 | 2 | 0
5 | 3 | 0
You can use after trigger for user table.
Create Trigger tr_user on Users
After Insert
AS Begin
INSERT UserTest(USER_ID, TEST_ID, Completed)
Select I.USER_ID, t.TEST_ID, 0
From Inserted I, Tests t
END
Here's a SQL Fiddle that finds missing records and inserts them.
SQL Fiddle
The SELECT:
select u.user_id, t.test_id, 0 as Completed
from users u
cross join tests t
where not exists (
select 1
from usertests ut
where ut.user_id = u.user_id and ut.test_id = t.test_id)
Adding insert into UserTests (User_Id, Test_Id, Completed) before the select will insert these records.
You can add a user id on to the where clause to do it for a single user if required. It is re-runnable so it won't re-insert test ids for a user that already has them, but will add new ones if new tests are introduced.

Sql Server query with date filter

I have a table like this;
ID int,
OrderedDate DateTime
I want to select only records of followed month.
For example result set:
ID OrderedDate
110 January
110 February
200 January
200 February
How can I write this query?
I think you want list of months that ID has orders in but with the months sorted by the month number instead of the name?
create table test21210
(
id int,
OrderedDate datetime
)
go
insert test21210 (id, OrderedDate) values (110, '1/1/2010')
insert test21210 (id, OrderedDate) values (110, '1/5/2010')
insert test21210 (id, OrderedDate) values (110, '1/10/2010')
insert test21210 (id, OrderedDate) values (110, '2/2/2010')
insert test21210 (id, OrderedDate) values (110, '2/4/2010')
insert test21210 (id, OrderedDate) values (110, '2/6/2010')
insert test21210 (id, OrderedDate) values (200, '1/3/2010')
insert test21210 (id, OrderedDate) values (200, '1/5/2010')
insert test21210 (id, OrderedDate) values (200, '1/7/2010')
insert test21210 (id, OrderedDate) values (200, '1/9/2010')
insert test21210 (id, OrderedDate) values (200, '2/3/2010')
insert test21210 (id, OrderedDate) values (200, '2/5/2010')
insert test21210 (id, OrderedDate) values (200, '2/7/2010')
insert test21210 (id, OrderedDate) values (200, '2/9/2010')
go
with idmonth (id, MonthNumber) as
(
select id, MONTH(ordereddate) as 'MonthNumber'
from test21210
group by id, MONTH(ordereddate)
)
select id, DATENAME(MONTH, STR(MonthNumber)+'/1/2000')
from idmonth
order by id, MonthNumber
The question seems a bit unclear. But the example makes it look like you are wanting to sort by ID then by month name. If so, then I think this will do it. I don't have SQL Server to test it, so I'm sure it has syntax or other errors.
SELECT ID, DATENAME(month, OrderedDate) AS OrderedDate from table
ORDER BY 1, MONTH( OrderedDate )