MySQL: select and divide by count using group by - mysql

Here's a data set of my table
ID |groupID| Start | End | SegStart | SegEnd | something
-------------------------------------------------------------------
1 | 1 | 0.234 | 0.345 | 0.345 | 0.677 | 0
2 | 1 | 0.234 | 0.345 | 0.346 | 0.678 | 0
3 | 1 | 0.234 | 0.345 | 0.347 | 0.679 | 0
4 | 1 | 0.234 | 0.345 | 0.348 | 0.680 | 1
5 | 2 | 0.345 | 0.567 | 0.568 | 0.570 | 0
6 | 2 | 0.345 | 0.567 | 0.569 | 0.571 | 1
7 | 3 | 0.567 | 0.678 | 0.679 | 0.681 | 0
8 | 3 | 0.567 | 0.678 | 0.680 | 0.682 | 0
9 | 3 | 0.567 | 0.678 | 0.681 | 0.683 | 1
I want to calculate a value from the Start / End columns as well as the SegStart / SegEnd columns where something = "1" and then divide this value by the number of items in a group (group 1 has 4 items, group 2 has 2, group 3 has 3, etc)
I've tried this query, but it gives me the error "Subquery returns more than 1 row"
select (((End - Start) - (SegEnd - SegStart)) /
(select count(*) as NumSeg from table group by groupID)) as NewValue
from table where something = "1";
I would like a list of the new value for each group, kind of like this (values are imaginary):
groupID | NewValue
--------------------
1 | 0.102
2 | 0.110
3 | 0.036

You could try this:
CREATE TABLE mytable(
ID INTEGER NOT NULL PRIMARY KEY
,groupID INTEGER NOT NULL
,Start NUMERIC(11,3) NOT NULL
,End NUMERIC(7,3) NOT NULL
,SegStart NUMERIC(11,3) NOT NULL
,SegEnd NUMERIC(11,3) NOT NULL
,something BIT NOT NULL
);
INSERT INTO mytable(ID,groupID,Start,End,SegStart,SegEnd,something) VALUES (1,1,0.234,0.345,0.345,0.677,0);
INSERT INTO mytable(ID,groupID,Start,End,SegStart,SegEnd,something) VALUES (2,1,0.234,0.345,0.346,0.678,0);
INSERT INTO mytable(ID,groupID,Start,End,SegStart,SegEnd,something) VALUES (3,1,0.234,0.345,0.347,0.679,0);
INSERT INTO mytable(ID,groupID,Start,End,SegStart,SegEnd,something) VALUES (4,1,0.234,0.345,0.348,0.680,1);
INSERT INTO mytable(ID,groupID,Start,End,SegStart,SegEnd,something) VALUES (5,2,0.345,0.567,0.568,0.570,0);
INSERT INTO mytable(ID,groupID,Start,End,SegStart,SegEnd,something) VALUES (6,2,0.345,0.567,0.569,0.571,1);
INSERT INTO mytable(ID,groupID,Start,End,SegStart,SegEnd,something) VALUES (7,3,0.567,0.678,0.679,0.681,0);
INSERT INTO mytable(ID,groupID,Start,End,SegStart,SegEnd,something) VALUES (8,3,0.567,0.678,0.680,0.682,0);
INSERT INTO mytable(ID,groupID,Start,End,SegStart,SegEnd,something) VALUES (9,3,0.567,0.678,0.681,0.683,1);
select A.GROUPID, ((End - Start) - (SegEnd - SegStart)) / B.NumSeg AS V1
from mytable A
INNER JOIN (select GROUPID, count(*) as NumSeg from mytable group by GROUPID) B ON A.GROUPID = B.GROUPID
where something = "1";
Output:
GROUPID V1
1 1 -0,0552500
2 2 0,1100000
3 3 0,0363333

Related

MySQL : Update Table upon certain conditions

I have 2 tables , master and current table( refreshed very hr).
Both the table shave same structure:
Chk | description |state | date
I need to update / append ( add the new row ) into the master table if :
1) rows that have new IDs or
2) if a particular variable ( 'state' in this case) has changed. I tried to do it using below without success :
INSERT into AGILE_TICKETS_DLY
SELECT * FROM CURR_AGILE_TICKETS curr
WHERE EXISTS (SELECT * FROM AGILE_TICKETS_DLY mstr
WHERE (curr.chk != mstr.chk) OR ( curr.chk = mstr.chk and
mstr.state != curr.state))
Any pointers on how to achieve this ?
You can try this pair of queries:
-- insert new rows
insert into agile_tickets_dly
select * from curr_agile_tickets
where chk not in (select chk from agile_tickets_dly);
-- update updated rows
update agile_tickets_dly x
join
(
select b.chk chk,b.description description,b.state state,b.date date
from agile_tickets_dly a, curr_agile_tickets b
where
a.chk=b.chk and
(a.description != b.description or a.state != b.state or a.date != b.date)
) y
on x.chk=y.chk
set x.description = y.description, x.state= y.state, x.date = y.date;
Illustration:
select * from agile_tickets_dly;
+------+-------------+---------+------------+
| chk | description | state | date |
+------+-------------+---------+------------+
| 0 | desc-0 | state-1 | 01-01-2017 |
| 1 | desc-1 | state-1 | 01-01-2018 |
| 2 | desc-2 | state-2 | 01-02-2018 |
| 3 | desc-3 | state-3 | 01-03-2018 |
+------+-------------+---------+------------+
-- one new row with chk=4, three updated rows with chk=1,2,3
select * from curr_agile_tickets;
+------+----------------+-----------------+----------------+
| chk | description | state | date |
+------+----------------+-----------------+----------------+
| 0 | desc-0 | state-1 | 01-01-2017 |
| 1 | desc-1 | state-1 | date-1-updated |
| 2 | desc-2-updated | state-2 | 01-02-2018 |
| 3 | desc-3 | state-3-updated | 01-03-2018 |
| 4 | desc-4 | state-4 | 01-04-2018 |
+------+----------------+-----------------+----------------+
-- after executing the two queries
select * from agile_tickets_dly;
+------+----------------+-----------------+----------------+
| chk | description | state | date |
+------+----------------+-----------------+----------------+
| 0 | desc-0 | state-1 | 01-01-2017 |
| 1 | desc-1 | state-1 | date-1-updated |
| 2 | desc-2-updated | state-2 | 01-02-2018 |
| 3 | desc-3 | state-3-updated | 01-03-2018 |
| 4 | desc-4 | state-4 | 01-04-2018 |
+------+----------------+-----------------+----------------+
I tried to do this in 2 separate steps:
1) First I append all new rows with IDs : this worked
INSERT into AGILE_TICKETS_DLY
SELECT * FROM CURR_AGILE_TICKETS curr
WHERE not EXISTS (SELECT * FROM AGILE_TICKETS_DLY mstr
WHERE (curr.chk = mstr.chk));
But then, I tried to do below got an error
2) Then replace the 'State' variable with new value:
INSERT into AGILE_TICKETS_DLY_1 (state)
SELECT state
from CURR_AGILE_TICKETS_1 curr
where exists ( select * from AGILE_TICKETS_DLY_1 mstr where curr.chk =
mstr.chk);
But this gives me an error :
SQL Error (1364) : Field 'chk' doesn't have a default value.
What does that mean ?

How i can add more condition to mysql query?

Table name is Sample
id name status date
1 ddd 1 2015-03-11
2 dddd 1 2015-03-12
3 dfdfgfg 0 2015-03-11
4 ererre 1 2015-03-19
5 eeeerer 0 2015-03-03
Here is the table, - this is query I am adding to get the result. I want the result from the table where date should not be expired if the status is set to 1 and no condition if the status is zero. So it should display. So I made the query like this
select * from sample where status='1' AND date>Now() OR status='0'
I am getting the result as like this which is correct
3 dfdfgfg 0 2015-03-11
4 ererre 1 2015-03-19
5 eeeerer 0 2015-03-03
But I want to add more queries to the same, how i can add more condition to above query?
You have to put the old condition and the new one in parenthesis , then use an AND to link them:
select * from sample
where (status='1' AND date>Now() OR status='0')
AND (new condition 1)
AND (new condition 2) ...
SELECT * FROM TABLE_NAME WHERE expiry_date > NOW()
Try using Union / Union All which soever suffice your requirement
Sample code with example from your data
create table sample(id INT,name CHAR(10), status INT, date_e DATE);
INSERT INTO sample VALUES(1, 'ddd',1,'2015-03-11');
INSERT INTO sample VALUES(2, 'dddd',1,'2015-03-12');
INSERT INTO sample VALUES(3, 'dfdfgfg',0,'2015-03-11');
INSERT INTO sample VALUES(4, 'ererre',1,'2015-03-19');
INSERT INTO sample VALUES(5, 'eeeerer',0,'2015-03-03');
SELECT * FROM sample;
+------+---------+--------+------------+
| id | name | status | date_e |
+------+---------+--------+------------+
| 1 | ddd | 1 | 2015-03-11 |
| 2 | dddd | 1 | 2015-03-12 |
| 3 | dfdfgfg | 0 | 2015-03-11 |
| 4 | ererre | 1 | 2015-03-19 |
| 5 | eeeerer | 0 | 2015-03-03 |
+------+---------+--------+------------+
5 rows in set (0.00 sec)
mysql> select * from sample where status='1' AND date_e>Now()
-> UNION ALL
-> select * from sample where status='0';
+------+---------+--------+------------+
| id | name | status | date_e |
+------+---------+--------+------------+
| 4 | ererre | 1 | 2015-03-19 |
| 3 | dfdfgfg | 0 | 2015-03-11 |
| 5 | eeeerer | 0 | 2015-03-03 |
+------+---------+--------+------------+
3 rows in set (0.00 sec)

Query to get values of one table which are not there in string column of another table, also less than a particular datetime value

I have a two tables :
mysql> select * from quizquestionbank;
| ID | QuestionFilePath | CorrectAnswer | EndDate |
--------------------------------------------------------------
| 1 | p.wav | 1 |2014-05-12 12:00:00 |
| 2 | q.wav | 2 |2014-05-12 12:00:00 |
| 3 | a.wav | 3 |2014-05-12 12:00:00 |
| 4 | b.wav | 1 |2014-05-12 12:00:00 |
| 5 | m.wav | 3 |2014-05-12 12:00:00 |
Second table is :
mysql> select * from quizuserdetails;
| ID | MSISDN | QuestionIdDetails | AnswerRecord |
--------------------------------------------------
| 1 | 235346 | 1,3,4,5 | S,F,S,F |
| 2 | 564574 | 4,5,67,88 | F,S,F,s |
| 3 | 500574 | 5,55,66,44,2 | F,F,F,F |
I want to get the IDs from table 1 which :
1. are not there in QuestionIdDetails column of second table and
2. less than current date and time.
Following Query gives me records required for first point:
Select qb.ID,qb.EndDate
from quizquestionbank qb
left join quizuserdetails qd
on find_in_set(qb.id, QuestionIdDetails) > 0
and msisdn = '235346'
where qd.id is null
But for second requirement following query gives error :
Select *
from predictionfootball
where '2014-05-10 00:00:00' <
(Select qb.ID,qb.EndDate
from quizquestionbank qb
left join quizuserdetails qd
on find_in_set(qb.id, QuestionIdDetails) > 0
and msisdn = '235346'
where qd.id is null)
Please tell me the way to do it.
Try that:
Select qb.ID,qb.EndDate
from quizquestionbank qb
left join quizuserdetails qd
on find_in_set(qb.id, QuestionIdDetails) > 0
and msisdn = '235346'
where qd.id is null
AND qb.EndDate < '2014-05-10 00:00:00' ------> added this line

Update the next row of the target row in MySQL

Suppose I have a table that tracks if a payment is missed like this:
+----+---------+------------+------------+---------+--------+
| id | loan_id | amount_due | due_at | paid_at | missed |
+----+---------+------------+------------+---------+--------+
| 1 | 1 | 100 | 2013-08-17 | NULL | NULL |
| 5 | 1 | 100 | 2013-09-17 | NULL | NULL |
| 7 | 1 | 100 | 2013-10-17 | NULL | NULL |
+----+---------+------------+------------+---------+--------+
And, for example, I ran a query that checks if a payment is missed like this:
UPDATE loan_payments
SET missed = 1
WHERE DATEDIFF(NOW(), due_at) >= 10
AND paid_at IS NULL
Then suppose that the row with id = 1 gets affected. I want the amount_due of row with id = 1 be added to the amount_due of the next row so the table would look like this:
+----+---------+------------+------------+---------+--------+
| id | loan_id | amount_due | due_at | paid_at | missed |
+----+---------+------------+------------+---------+--------+
| 1 | 1 | 100 | 2013-08-17 | NULL | 1 |
| 5 | 1 | 200 | 2013-09-17 | NULL | NULL |
| 7 | 1 | 100 | 2013-10-17 | NULL | NULL |
+----+---------+------------+------------+---------+--------+
Any advice on how to do it?
Thanks
Take a look at this :
SQL Fiddle
MySQL 5.5.32 Schema Setup:
CREATE TABLE loan_payments
(`id` int, `loan_id` int, `amount_due` int,
`due_at` varchar(10), `paid_at` varchar(4), `missed` varchar(4))
;
INSERT INTO loan_payments
(`id`, `loan_id`, `amount_due`, `due_at`, `paid_at`, `missed`)
VALUES
(1, 1, 100, '2013-09-17', NULL, NULL),
(3, 2, 100, '2013-09-17', NULL, NULL),
(5, 1, 100, '2013-10-17', NULL, NULL),
(7, 1, 100, '2013-11-17', NULL, NULL)
;
UPDATE loan_payments AS l
LEFT OUTER JOIN (SELECT loan_id, MIN(ID) AS ID
FROM loan_payments
WHERE DATEDIFF(NOW(), due_at) < 0
GROUP BY loan_id) AS l2 ON l.loan_id = l2.loan_id
LEFT OUTER JOIN loan_payments AS l3 ON l2.id = l3.id
SET l.missed = 1, l3.amount_due = l3.amount_due + l.amount_due
WHERE DATEDIFF(NOW(), l.due_at) >= 10
AND l.paid_at IS NULL
;
Query 1:
SELECT *
FROM loan_payments
Results:
| ID | LOAN_ID | AMOUNT_DUE | DUE_AT | PAID_AT | MISSED |
|----|---------|------------|------------|---------|--------|
| 1 | 1 | 100 | 2013-09-17 | (null) | 1 |
| 3 | 2 | 100 | 2013-09-17 | (null) | 1 |
| 5 | 1 | 200 | 2013-10-17 | (null) | (null) |
| 7 | 1 | 100 | 2013-11-17 | (null) | (null) |
Unfortunately I don't have time at the moment to write out full-blown SQL, but here's the psuedocode I think you need to implement:
select all DISTINCT loan_id from table loan_payments
for each loan_id:
set missed = 1 for all outstanding payments for loan_id (as determined by date)
select the sum of all outstanding payments for loan_id
add this sum to the amount_due for the loan's next due date after today
Refer to this for how to loop using pure MySQL: http://dev.mysql.com/doc/refman/5.7/en/cursors.html
I fixed my own problem by adding a missed_at field. I put the current timestamp ($now) in a variable before I update the first row to missed = 1 and missed_at = $now then I ran this query to update the next row's amount_due:
UPDATE loan_payments lp1 JOIN loan_payments lp2 ON lp1.due_at > lp2.due_at
SET lp1.amount_due = lp2.amount_due + lp1.amount_due
WHERE lp2.missed_at = $now AND DATEDIFF(lp1.due_at, lp2.due_at) <= DAYOFMONTH(LAST_DAY(lp1.due_at))
I wish I could use just use LIMIT 1 to that query but it turns out that it's not possible for an UPDATE query with a JOIN.
So all in all, I used two queries to achieve what I want. It did the trick.
Please advise if you have better solutions.
Thanks!

Update table records satisfying a condition related to the same table

I'm trying to update a date column of records satisfying following condition:
Column STATION has to be the same as STATION from record with FILTER_NR = x
AND STATUS IN (11, 12, 13)
AND FILTER_NR != x
If x = 3 the UPDATE Statement, I'm looking for, should change the Table FILTER from:
+-----------+------------+---------+---------+
| FILTER_NR | PROBEDATE | STATION | STATUS |
+-----------+------------+---------+---------+
| 1 | 2011-06-01 | 1 | 10 |
| 2 | 2011-06-02 | 1 | 11 |
| 3 | 2011-06-03 | 1 | 12 |
| 4 | 2011-06-04 | 2 | 13 |
+-----------+------------+---------+---------+
to:
+-----------+------------+---------+----------+
| FILTER_NR | PROBEDATE | STATION | STATUS |
+-----------+------------+---------+----------+
| 1 | 2011-06-01 | 1 | 10 | -> not changed
| 2 | 2011-06-01 | 1 | 11 | -> changed
| 3 | 2011-06-03 | 1 | 12 | -> not changed
| 4 | 2011-06-04 | 2 | 13 | -> not changed
+-----------+------------+---------+----------+
I began with following SQL Statement, do you know how I can complete it?
UPDATE FILTER SET PROBEDATE = ADDDATE(PROBEDATE, -1)
WHERE FILTER_NR IN (...);
This should work for you:
UPDATE `FILTER` `F`
INNER JOIN `FILTER` `F1` ON `F1`.`FILTER_NR` = 3 AND `F1`.`STATION` = `F`.`STATION`
SET `F`.`PROBEDATE` = CURDATE()
WHERE `F`.`FILTER_NR` != 3
AND `F`.`STATUS` IN (11, 12, 13);
In my example, I've set PROBEDATE to the current date but please feel free to set it to what you might like.
Hope this helps!
You could ty something like this:
UPDATE FILTER
SET PROBEDATE = PROBEDATE - inteval 1 day
WHERE STATUS IN (11,12,13)
AND FILTER_NR != 3
AND STATION IN
(
SELECT STATION
FROM (
SELECT *
FROM FILTER
) as SubQueryAlias
WHERE FILTER_NR = 3
)