how to subtract two resultant values in mysql - 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.

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;

select rows in mysql with latest date for each quiz_id repeated multiple times

I have a table where each quiz ID is repeated multiple times. there is a date in front of each quiz id in each row. I want to select entire row for each quiz ID where date is latest with user. The date format is mm/dd/YYYY.
Sample -
USER_ID Quiz_id Name Date Marks .. .. ..
1 2 poly 4/3/2020 27
1 2 poly 4/3/2019 98
1 4 moro 4/3/2020 09
2 5 cat 4/12/2015 87
2 4 moro 4/3/2009 56
2 6 PP 4/3/2011 76
3 2 poly 4/3/2020 12
3 2 poly 5/3/2020 09
3 7 dog 4/3/2011 23
I want result look like this:Result
USER_ID Quiz_id Name Date Marks .. .. ..
1 2 poly 4/3/2020 27
1 4 moro 4/3/2020 09
2 5 cat 4/12/2015 87
2 4 moro 4/3/2009 56
2 6 PP 4/3/2011 76
3 2 poly 5/3/2020 09
3 7 dog 4/3/2011 23
You can use rank function to get the desired result:
Demo
SELECT A.* FROM (
SELECT A.*, RANK() OVER(PARTITION BY USER_ID,QUIZ_ID, NAME ORDER BY DATE DESC) RN FROM
Table1 A ORDER BY USER_ID) A WHERE RN = 1 ORDER BY USER_ID, QUIZ_ID;
I don't have MySQL installed so you will need to test and report back. The general idea is to identify the row of interest using max and a group by (table t). As the Date column appears to be text column (MySQL uses the format YYYY-MM-DD for dates) you will need to convert it to a date with str_to_date() so you can use the max() aggregate function. Finally, join with the original table (here table t2 to do the date conversion), as only the aggregate column(s) and columns named in the group by are well defined (in table t1), i.e.:
select USER_ID, Quiz_id, Date, Marks from (
select USER_ID, Quiz_id, max(str_to_date(Date, '%m/%d/%Y')) as Date2 from quiz group by 1, 2
) as t natural join (
select *, str_to_date(Date, '%m/%d/%Y') Date2 from Quiz
) as t2;
I don't recall off-hand but Date might be reserved word, in which case you will need to quote the column name, or ideally rename said column to use a better name.
Also, the original table is not in 3rd normal form as Quiz_id depends on Name. Quiz_id, as implied, should be a foreign key to a lookup table that holds the Name.

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

Group by with sum doesn't return correct result

Say a table has this schema :
grp | number
1 | 10
1 | 10
1 | 10
2 | 30
2 | 30
3 | 20
Note that each unique grp has a unique number even if there are more than 1 grp. I'm looking to sum all numbers for each unique grp.
So I want to group my table by grp to have this :
grp | number
1 | 10
2 | 30
3 | 20
And then get the sum which is now 60, but without grouping it gets me 110 as it calculates the sum of everything without grouping. All in one query, with no sub-queries if possible.
I've tried doing the following :
SELECT sum(number) as f
FROM ...
WHERE ...
GROUP BY grp
But this doesn't work, it returns multiple results and not the single result of the sum. What am I doing wrong?
You can use subquery to select unique records & do the sum:
select sum(number)
from (select distinct grp, number
from table t
) t;
If you group by the group, then you'll get one result for each group. And it won't take into account the fact that you only want to use the value from each group once.
To get your desired result, taking one row from each group, you first need to make a subquery selecting DISTINCT group/number combinations from the table, and then SUM that.
SELECT
sum(`number`) as f
FROM
(SELECT DISTINCT `grp`, `number` FROM table1) g
This will output 60.
Demo: https://dbfiddle.uk/?rdbms=mysql_8.0&fiddle=8a3b346041731a4b4c85f4e151c10f70

MySQL: Get all rows if specific value reached after date

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');