MySQL: Get all rows if specific value reached after date - mysql

In MySQL, I want to find all the rows where the value of a column went to 0 after a specific date.
So, given the data:
cat value date
a 95 2015-09-01
a 78 2015-10-01
a 0 2015-11-01
a 0 2015-12-01
b 129 2015-09-01
b 230 2015-10-01
b 201 2015-11-01
b 140 2015-12-01
In this case, I want to run a query that asks:
Which categories have 0 value after 10/1/2015 and had a positive value before 11/1/2015?
The result should show category "a".
I suspect is a nested select statement, but haven't quite figured it out.

select * from yourTable where value = 0 and date > '2015-10-01' and cat in (
select distinct cat where value > 0 and date < '2015-11-1'
)
Explanation: you can split the query to two parts - the inner query with the in statement is in charge of getting the cat ID's that were positive before 11/1/15, and the where value = 0 and date > '2015-10-01' will give you those that are 0 after 10/1/15

Building off what Nir Levy said, if you only want the category to be returned, you can select just the distinct values for cat:
SELECT DISTINCT cat
FROM stack_test.your_table
WHERE value = 0 AND date > '2015-10-01' AND
cat IN (SELECT cat FROM stack_test.mysql_rows WHERE value > 0 AND date < '2015-11-01');

Related

Select less nearest date from table [group by and order by]

I'm trying to find the nearest date for each group Type, Subtype, s_stype, category_id. If there is no date found take a with default value:
Sample data :
Type
subtype
s_stype
category_Id
date
1
1
1
211
20000000
1
1
1
211
30000000
1
1
2
211
20000000
1
1
2
211
20000000
1
1
3
211
null
1
1
2
311
50000000
1
1
2
311
40000000
1
1
2
311
null
Query:
Select *
from Table
where date <= input_date or date is null
group by Type, Subtype, s_stype, category_id
order by date desc
The query should take less nearest date for each type, subtype, s_stype, category.
For example, given input_date = 25000000:
Type
subtype
s_stype
category_Id
date
1
1
1
211
20000000
1
1
2
211
20000000
1
1
3
211
null
1
1
2
311
null
the query should give above result instead it gives incorrect row that takes a first row which satisfy where condition of given group criteria
As i have used mysql 5.7 so i need solution without window functions solution like the above
Getting the best row per group means there does not exist a better row for the group. And "closer" means that the absolute value of the difference of the two dates is smaller. This is how my query below works.
As your dates in your example are integers, I am showing integer math here. If you are working with real dates, you must use DATEDIFF instead of subtraction, because MySQL has a flaw concerning this allowing subtracting one date from another but returning some number that doesn't seem to have a meaning instead of returning an interval or a value of a predefined unit such as dates.
select *
from mytable
where not exists
(
select null
from mytable better
where better.type = mytable.type
and better.subtype = mytable.subtype
and better.s_stype = mytable.s_stype
and better.category_id = mytable.category_id
and
(
abs(better.date - 25000000) < abs(mytable.date - 25000000)
or
(better.date is not null and mytable.date is null)
)
)
order by type, subtype, s_stype, category_id, date;

ierate each row and pass the values of two columns to a query and append each result to the table

I have a table with the structure below with name table1
sid userid date result
1 169110 2020-01-03 (null)
2 178662 2020-01-06 (null)
3 165381 2020-01-07 (null)
5 368031 2020-01-08 (null)
7 163626 2020-01-09 (null)
Now I need to send each row values of cft.userid and cft.date to a mysql query (query is below) which gives the value of the result for each row
UPDATE collision_fact_table cft
SET cft.on_time_completion = (
SELECT DISTINCT
CONCAT(ROUND(NULLIF(SUM(facttable.compliant), 0) / NULLIF(SUM(facttable.Occurences), 0) * 100), '%') AS `Percentage Completed`
FROM fd_dw.ComplianceFactTable facttable
WHERE (CAST(facttable.`CourseModule_dueDateID` AS date) - cft.collision_date) <= 0
AND facttable.UserLicenseInUsing = 1
AND (facttable.`CourseModule_dueDateID` > 0)
AND facttable.UserId = cft.userid
GROUP BY facttable.`UserID`);
For example, when i send first row values of userid 169110 and date value to the above query, i will get result as 69 and i need to update 69 to the table1 like below
sid userid date result
1 169110 2020-01-03 69
Similarly it should iterate for all the rows and table1 should get updated like below
sid userid date result
1 169110 2020-01-03 69
2 178662 2020-01-06 55
3 165381 2020-01-07 64
5 368031 2020-01-08 48
7 163626 2020-01-09 56
But when i tried to execute the update query, its giving me error Unknown column 'cft.date' in field list
Please anyone help me
I think you basically want a correlated subquery:
update table1 t1
set result = (
select cd.result
from ...
where
cd.ScheduleDateID <= t1.date
and cd.CourseModuleComplete_DateID <= t1.date
and cd.UserId = t1.userid
)
You don't give much details about the subquery itself. It is critical that it should return one row, and one row only:
if it returns no rows, then the result of the corresponding row in table1 will be set to null (regardless of its original value) - this might, or might not be what you want
if it returns more than one row, then the query will error

Select count from another table

I have two tables: ToDoList & ToDotasks
I need to write a query that will return me the column ot ToDoList as well as a count of incomplete tasks i.e. where taskstatus=0 for the ToDotasks table
My query:
SELECT *,(select count(*) from todotasks where taskstatus = 0 group by
listid) as TotalIncomplete FROM dbo.ToDoList
Error: Subquery returned more than 1 value. This is not permitted when the subquery follows =, !=, <, <= , >, >= or when the subquery is used as an expression.
ToDoList:
ListID ListName
1 List 5600
2 List 22
3 List 30
4 List 4
5 List 1
ToDotasks
taskid ListID taskStatus
3 2 0
6 3 0
14 3 0
16 3 0
19 4 1
36 1 0
38 1 1
39 1 0
40 2 0
41 2 0
What I am after:
ListID ListName TotalIncomplete
1 List 5600 2
2 List 22 3
3 List 30 3
4 List 4 0
5 List 1 0
Please try the following...
SELECT ToDoList.ListID AS ListID,
ToDoList.ListName AS ListName,
COUNT( incompleteTasks.ListID ) AS IncompleteTaskCount
FROM ToDoList
LEFT JOIN
(
SELECT ListID AS ListID
FROM ToDoTasks
WHERE taskStatus = 0
) incompleteTasks ON ToDoList.ListID = incompleteTasks.ListID
GROUP BY ToDoList.ListID
ORDER BY ToDoList.ListID;
The logic I used was...
To get a count of incomplete tasks we would first need a list of those tasks that have a taskStatus of 0. The taskid will be irrelevant to the count and once tested so will taskStatus be irrelevant. Therefore this list only needs to include each qualifying task's ListID. I have given this list the name incompleteTasks.
ToDoList LEFT JOIN incompleteTasks will give us a table consisting of each value from incompleteTasks with its corresponding values from ToDoList. Where a record from ToDoList does not have any corresponding records in incompleteTasks we get the values from ToDoList accompanied by a NULL value.
By grouping the LEFT JOINed list on its value of ListID from List we achieve a grouping that corresponds with our desired output. We then use COUNT() to count the number of times that ListID appears in our joined list's field from incompleteTasks. Note : COUNT() does not count NULL values.
The list resulting from the above can then be sorted by the value of ListID from List using ORDER BY ToDoList.ListID.
If you have any questions or comments, then please feel free to post a Comment accordingly.
Its pretty straight forward.. Here is the solution
select ToDoList.lisid, ToDoList.lastname, count(ToDoTasks.taskstatus) from
ToDoList JOIN ToDoTasks ON ToDoList.listid = ToDoTasks.listid
where ToDoTasks.taskstatus = 0
group by ToDoList.listname,ToDoList.listid
Updated Query with your table names....
Hope this helps. Cheers !!!

how to subtract two resultant values in mysql

Say I have a table tableA and my query is
select id,
if(cond1, value, 0) firstval,
if(cond2, value, 0) secondval,
firstval-secondval diff
from tableA
The above query gives Unknown column firstval in field list error. I know I can calculate diff as if(cond1, value, 0)-if(cond2, value, 0) diff but i don't want to add condition again and without inner/sub queries.
EDIT: My abstract idea as follows
Table structure
id | type | recorddate | value
=========================================
1 A 2015-12-17 9
2 B 2015-12-19 5
3 A 2016-01-13 31
4 B 2016-01-14 23
5 A 2016-01-31 44
6 B 2016-02-07 38
and so on...
Query:
select
type,
if(max(recorddate), value, 0) firstval,
if(secondmax(recorddate), value, 0) secndval,
firstval-secndval diff
from table
where month(recorddate)=1
group by type with rollup
Resultant table based on above query:
type | firstval | secndval | diff
======================================
A 44 31 13
B 23 5 18
Total 67 36 31
Add sub-query
select *, firstval-secondval diff
from
(select id, if(cond1, value, 0) firstval, if(cond2, value, 0) secondval
from tableA
) t
Do you want to get subtract two resultant values. Am i right?
So that for firstval check with one condition if condition true then get that value otherwise firstval value is 0. Do the same for secondval also. So that you will not get unknown column error. First of all you should have column name firstval and secondval.
Select firstval-secondval as total from tableA;
It will work for simple subtract.

Incorrect GROUP by function due to CONCAT

I am using SUM() to count lines with multiple conditions in the following manner
SELECT date(time),
SUM(CASE WHEN crit1 = 1 AND crit2 NOT LIKE CONCAT('%',table1.id,'%') THEN 1 ELSE 0 END)
FROM table1, table2
GROUP BY date(time)
However what I noticed is that # of items that are counted is a multiple of items in the table1. So if there are 100 items that meet crit1 and crit2 criteria, and there are 5 items in table1, it would give me 500 items summed.
I added and removed items from table1 and it proportionally affected the SUM clause, to verify this.
How can it be summed without double counting for every case in CONCAT, or maybe a better way of counting all together?
Data structure:
table1 table2
id name time crit1 crit2
123 A 2013-05-15 05:00:00 1 456
234 B 2013-05-15 05:00:00 2 789
345 C 2013-05-15 05:00:00 1 678
Note: IDs are unique
Desired output:
2013-05-15 2
I believe you want this:
SELECT date(time), COUNT(crit2)
FROM table2
WHERE
table2.crit1 = 1
AND
table2.crit2 NOT IN (SELECT id FROM table1)
GROUP BY date(time)