Calculate difference between two row amount in MySQL - mysql

I am having a table with which calculates balance, where I have these columns in the table:
> describe tbl_credit_log
+------------------+------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+------------------+------------------+------+-----+---------+----------------+
| id | int(10) unsigned | NO | PRI | NULL | auto_increment |
| visitor_id | int(10) unsigned | YES | MUL | NULL | |
| post_owner_id | int(10) unsigned | YES | MUL | NULL | |
| post_id | int(10) unsigned | YES | MUL | NULL | |
| balance | double(50,6) | YES | | NULL | |
| credits | double(50,6) | YES | | NULL | |
| debits | double(50,6) | YES | | NULL | |
| trans_id | varchar(255) | NO | | NULL | |
| trans_amount | double(50,6) | YES | | NULL | |
| earningtype | varchar(15) | NO | | NULL | |
| created_at | timestamp | YES | | NULL | |
| updated_at | timestamp | YES | | NULL | |
+------------------+------------------+------+-----+---------+----------------+
Where here is the few entries from which I want to do the calculations :
+---------+------------+---------------+---------+------------------+-------------+-----------+--------+---------------------+
| id | visitor_id | post_owner_id | post_id | advertisement_id | balance | credits | debits | created_at |
+---------+------------+---------------+---------+------------------+-------------+-----------+--------+---------------------+
| 4331666 | 11006 | 11 | NULL | NULL | 3639.624400 | 22.500000 | NULL | 2018-08-10 05:45:37 |
| 4364034 | 7206 | 11 | NULL | NULL | 5139.607900 | 22.500000 | NULL | 2018-08-10 11:02:52 |
| 4377238 | 4353 | 11 | NULL | NULL | 5162.107900 | 22.500000 | NULL | 2018-08-10 12:52:01 |
| 4485288 | 9664 | 11 | NULL | NULL | 5184.607900 | 22.500000 | NULL | 2018-08-11 08:58:19 |
| 4544185 | 11709 | 11 | NULL | NULL | 5207.107900 | 22.500000 | NULL | 2018-08-11 19:06:52 |
| 4550728 | 11970 | 11 | NULL | NULL | 5229.607900 | 22.500000 | NULL | 2018-08-11 20:39:36 |
| 4607317 | 12021 | 11 | NULL | NULL | 5252.107900 | 22.500000 | NULL | 2018-08-12 07:29:17 |
| 4629660 | 11926 | 11 | NULL | NULL | 5274.607900 | 22.500000 | NULL | 2018-08-12 09:18:56 |
| 4725299 | 12088 | 11 | NULL | NULL | 5297.107900 | 22.500000 | NULL | 2018-08-13 01:54:53 |
| 4725347 | 10253 | 11 | NULL | NULL | 5319.607900 | 22.500000 | NULL | 2018-08-13 08:29:46 |
| 4725357 | 12140 | 11 | NULL | NULL | 5342.107900 | 22.500000 | NULL | 2018-08-13 09:27:44 |
+---------+------------+---------------+---------+------------------+-------------+-----------+--------+---------------------+
here we have difference (more then 50) in amount on id number4364034 which I want to find in whole database where user id will be post_owner_id as foreign key.
I want to get all the post_owner_id who have difference in the amount and their created_at.
So the expected results will be something like this
+---------+------------+---------------+---------+------------------+-------------+-----------+--------+---------------------+
| id | visitor_id | post_owner_id | post_id | advertisement_id | balance | credits | debits | created_at |
+---------+------------+---------------+---------+------------------+-------------+-----------+--------+---------------------+
| 4364034 | 7206 | 11 | NULL | NULL | 5139.607900 | 22.500000 | NULL | 2018-08-10 11:02:52 |
+---------+------------+---------------+---------+------------------+-------------+-----------+--------+---------------------+
here we will have multiple post_owner_id. I am showing one post_owner_id because this result is only of one post owner id. But I want to get different post owner id who have difference balance is more then 50.
I am not able to figure out how can I do this. I want to compare prices on group_by post_owner_id and get the row where the difference amount is.

Consider the following:
DROP TABLE IF EXISTS my_table;
CREATE TABLE my_table
(id SERIAL PRIMARY KEY
,balance DECIMAL(12,6) NOT NULL
,created_at timestamp NOT NULL
);
INSERT INTO my_table VALUES
(4331666,3639.624400,'2018-08-10 05:45:37'),
(4364034,5139.607900,'2018-08-10 11:02:52'),
(4377238,5162.107900,'2018-08-10 12:52:01'),
(4485288,5184.607900,'2018-08-11 08:58:19'),
(4544185,5207.107900,'2018-08-11 19:06:52'),
(4550728,5229.607900,'2018-08-11 20:39:36'),
(4607317,5252.107900,'2018-08-12 07:29:17'),
(4629660,5274.607900,'2018-08-12 09:18:56'),
(4725299,5297.107900,'2018-08-13 01:54:53'),
(4725347,5319.607900,'2018-08-13 08:29:46'),
(4725357,5342.107900,'2018-08-13 09:27:44');
Option 1:
SELECT a.*
FROM
( SELECT x.*
, MIN(y.id) y_id
FROM my_table x
JOIN my_table y
ON y.created_at > x.created_at
GROUP
BY x.id
) a
JOIN my_table b
ON b.id = a.y_id
AND b.balance > a.balance + 50;
+---------+-------------+---------------------+---------+
| id | balance | created_at | y_id |
+---------+-------------+---------------------+---------+
| 4331666 | 3639.624400 | 2018-08-10 05:45:37 | 4364034 |
+---------+-------------+---------------------+---------+
Option 2:
SELECT id
, balance
, created_at
FROM
( SELECT x.*
, #i<balance-50 i
, #i:=balance
FROM my_table x
, (SELECT #i:=null) vars
ORDER
BY created_at
) n
WHERE i = 1;
+---------+-------------+---------------------+
| id | balance | created_at |
+---------+-------------+---------------------+
| 4364034 | 5139.607900 | 2018-08-10 11:02:52 |
+---------+-------------+---------------------+
You can adapt either of the techniques above to return either row

Related

MySQL select last row of each one user from a list of users in a table

Im trying to select from a Moodle table the last row of each user in a list.
my query is
SELECT *
FROM mdl_logstore_standard_log
WHERE eventname='\\core\\event\\user_enrolment_created'
AND courseid=34
AND relateduserid IN(120,128)
GROUP BY relateduserid;`
and the table that i use is :
MariaDB [****_*****]> describe mdl_logstore_standard_log;
+-------------------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------------------+--------------+------+-----+---------+----------------+
| id | bigint(10) | NO | PRI | NULL | auto_increment |
| eventname | varchar(255) | NO | | | |
| component | varchar(100) | NO | | | |
| action | varchar(100) | NO | | | |
| target | varchar(100) | NO | | | |
| objecttable | varchar(50) | YES | | NULL | |
| objectid | bigint(10) | YES | | NULL | |
| crud | varchar(1) | NO | | | |
| edulevel | tinyint(1) | NO | | NULL | |
| contextid | bigint(10) | NO | MUL | NULL | |
| contextlevel | bigint(10) | NO | | NULL | |
| contextinstanceid | bigint(10) | NO | | NULL | |
| userid | bigint(10) | NO | MUL | NULL | |
| courseid | bigint(10) | YES | MUL | NULL | |
| relateduserid | bigint(10) | YES | | NULL | |
| anonymous | tinyint(1) | NO | | 0 | |
| other | longtext | YES | | NULL | |
| timecreated | bigint(10) | NO | MUL | NULL | |
| origin | varchar(10) | YES | | NULL | |
| ip | varchar(45) | YES | | NULL | |
| realuserid | bigint(10) | YES | | NULL | |
+-------------------+--------------+------+-----+---------+----------------+
My Problem with this query is that it give me the first row for every userid in list, and i want the last. i tried order by id desc but nothing changed.
You can try this:
SELECT
L.*
FROM mdl_logstore_standard_log L
INNER JOIN
(
SELECT
relateduserid,
MAX(id) AS max_id
FROM mdl_logstore_standard_log
WHERE eventname='\\core\\event\\user_enrolment_created'
AND courseid=34
AND relateduserid IN(120,128)
GROUP BY relateduserid
)AS t
ON L.id = t.max_id
First getting the maximum auto increment id for those relateduserids then making an inner join between mdl_logstore_standard_log and t table would return your expected result.
Try this but i didnt test it
select * from mdl_logstore_standard_log where eventname='\\core\\event\\user_enrolment_created' and courseid=34 and relateduserid IN(120,128) GROUP BY relateduserid ORDER BY id DESC LIMIT 1;

How to add a date selection in sql

I want to be able to select classes that are starting on or after the next two hours up until the end of tomorrow's date but I am not sure of how to do this.
My current sql is below, I have only been able to select classes that are after today's date and after the current time. I want to be able to only return classes that start two hours after now up until the end of tomorrows date.
I am able to pass the current date and current time into my node.js function that will construct the sql statement. Also, I have access to moment.js library if I need to use this I could.
Any help would be appreciated.
SELECT DISTINCT b.name
, a.time
FROM class a
Inner join (SELECT class_id, count(clientid)
FROM bookings
GROUP BY class_id
HAVING count(clientid) < 10) as openClasses on
a.class_id = openClasses.class_id
JOIN class_detail b
ON a.class_id = b.id
JOIN branch c
ON a.branch_id = c.id
WHERE c.level <= ( SELECT d.level
FROM client d
WHERE d.facebook_id = 'xxxxxx'
)
AND a.date = '2016-08-17'
AND a.time >= '13.00.00';
My tables are as follows:
BOOKINGS
+-----------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-----------+-------------+------+-----+---------+-------+
| id | bigint(20) | NO | PRI | NULL | |
| CLIENT_ID | int(11) | NO | | NULL | |
| CLASS_ID | int(11) | NO | | NULL | |
| STATUS | varchar(10) | NO | | NULL | |
+-----------+-------------+------+-----+---------+-------+
mysql> show fields from BRANCH;
+---------------------+-------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+---------------------+-------------+------+-----+---------+----------------+
| id | int(10) | NO | PRI | NULL | auto_increment |
| NAME | char(50) | NO | | NULL | |
| CONTACT_NO | char(50) | YES | | NULL | |
| MAP_IMG_PATH | char(200) | YES | | NULL | |
| ADDRESS | char(200) | YES | | NULL | |
| LEVEL | int(2) | NO | | NULL | |
| LOCATION | int(10) | YES | | NULL | |
| SECTOR_NAME | varchar(45) | YES | | NULL | |
| SECTOR_MAP_IMG_PATH | char(200) | YES | | NULL | |
+---------------------+-------------+------+-----+---------+----------------+
mysql> show fields from CLIENT;
+--------------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+--------------+-------------+------+-----+---------+-------+
| id | int(10) | NO | PRI | NULL | |
| NAME | char(50) | NO | | NULL | |
| DOB | int(8) | NO | | NULL | |
| LOCAL_BRANCH | int(10) | YES | | NULL | |
| FACEBOOK_ID | char(50) | NO | | NULL | |
| START_DATE | int(8) | NO | | NULL | |
| EMAIL | char(50) | YES | | NULL | |
| PIN | int(4) | YES | | NULL | |
| END_DATE | int(8) | NO | | NULL | |
| LEVEL | int(2) | YES | | NULL | |
| TEL | varchar(20) | YES | | NULL | |
+--------------+-------------+------+-----+---------+-------+
mysql> show fields from CLASS_DETAIL;
+--------------+--------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+--------------+--------------+------+-----+---------+-------+
| id | int(10) | NO | PRI | NULL | |
| NAME | char(50) | NO | | NULL | |
| DESCRIPTION | char(200) | NO | | NULL | |
| CATEGORY | varchar(4) | YES | | NULL | |
| ACHIEVE_TYPE | char(200) | YES | | NULL | |
| IMG_M | varchar(200) | YES | | NULL | |
| IMG_F | varchar(200) | YES | | NULL | |
+--------------+--------------+------+-----+---------+-------+
mysql> show fields from CLASS;
+-----------+---------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-----------+---------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| CLASS_ID | int(10) | YES | | NULL | |
| BRANCH_ID | int(10) | NO | | NULL | |
| DURATION | int(3) | YES | | NULL | |
| DATE | date | NO | | NULL | |
| TIME | time | NO | | NULL | |
| STATUS | char(1) | NO | | NULL | |
+-----------+---------+------+-----+---------+----------------+
7 rows in set (0.11 sec)

mysql query using 4 tables to produce small report

I'm having trouble getting a query to work. 4 tables are used in this query. I want a report looking like this...
Name Success Failure
jdn 5 1
wer 0 3
I want to produce data for the last 24 hours. Here is a sample query I tried and didn't work.
select r.name as jid,
i.id as theid,
(select sum(counter) as scount
from WebServicesIfSummarySuccess
where id=theid
and dtime between date_sub(now(),interval 24 hour) and now()
and sum(counter) >0 and sum(counter) is not null
group by id
) as success,
(select sum(counter) as fcount
from WebServicesIfSummaryFailure
where id=theid
and dtime between date_sub(now(),interval 24 hour) and now()
and sum(counter) >0 and sum(counter) is not null
group by id
) as failure
from router r, interface i
where r.rid = i.rid
and r.name like '%wi%' ;
Here are the table layouts.
router
+-------+---------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------+---------------------+------+-----+---------+----------------+
| rid | int(11) unsigned | NO | PRI | NULL | auto_increment |
| name | char(120) | NO | MUL | | |
| pop | char(10) | NO | MUL | | |
| popid | tinyint(3) unsigned | NO | | 0 | |
+-------+---------------------+------+-----+---------+----------------+
interface
+-------------+---------------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------------+---------------------------+------+-----+---------+----------------+
| id | int(11) unsigned | NO | PRI | NULL | auto_increment |
| name | char(255) | NO | MUL | | |
| rid | int(11) | NO | MUL | 0 | |
| speed | bigint(11) | YES | | NULL | |
| description | char(255) | YES | | NULL | |
| status | enum('active','inactive') | YES | | active | |
+-------------+---------------------------+------+-----+---------+----------------+
Failure and Success are 2 separate tables
+---------+------------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+---------+------------------+------+-----+---------+-------+
| id | int(10) unsigned | NO | PRI | NULL | |
| dtime | datetime | NO | PRI | NULL | |
| counter | bigint(20) | NO | | NULL | |
| rate | int(11) | YES | | NULL | |
+---------+------------------+------+-----+---------+-------+

Complex MySQL Join with 3 tables and many2many relations

I have 3 tables person, account and subscription. Account belongs to Person as one to many and Account and Subscription are many to many.I need a sql which can select data from three tables.-
Person Tables
+----------------------------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+----------------------------+--------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| username | varchar(128) | NO | | NULL | |
| password | varchar(128) | NO | | NULL | |
| account_id | int(11) | NO | | NULL | |
+----------------------------+---------------+------+---------------+----------------+
Account table
+--------------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+--------------+--------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| yearly_renew | tinyint(1) | NO | | NULL | |
| date_joined | date | NO | | NULL | |
| last_renewed | datetime | YES | | NULL | |
| signup | tinyint(1) | NO | | NULL | |
| reason | varchar(100) | YES | | NULL | |
| yearly_total | int(11) | YES | | NULL | |
| total | int(11) | YES | | NULL | |
+--------------+--------------+------+-----+---------+----------------+
Account-Subscription table
+-----------------+---------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-----------------+---------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| account_id | int(11) | NO | MUL | NULL | |
| subscription_id | int(11) | NO | MUL | NULL | |
+-----------------+---------+------+-----+---------+----------------+
Subscription table
+-------------------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------------------+--------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| subscription_type | varchar(150) | YES | | NULL | |
| hold | tinyint(1) | NO | | NULL | |
| start_date | date | YES | | NULL | |
| end_date | date | YES | | NULL | |
| amount_paid | double | YES | | NULL | |
| date_paid | date | YES | | NULL | |
| transaction_id | int(11) | YES | | NULL | |
| free | tinyint(1) | NO | | NULL | |
+-------------------+--------------+------+-----+---------+----------------+
Expecting output in a single query -
OUTPUT
+-----------+------------+--------------+
| person.id | account.id | subscription.id |
+-----------+------------+--------------+
| 10 | 11 | 20 |
| 15 | 32 | 45 |
| 23 | 43 | null |
+--------+---------+-----------------+
try this. it may works properly...
SELECT p.Id AS person.id
,p.account_id AS account.id
,acsub.subscription_id as subscription.id
FROM Person AS p
LEFT JOIN Account-Subscription AS acsub ON p.account_id=acsub.account_id
SELECT p.Id AS person.id
,p.account_id AS account.id
,acsub.subscription_id as subscription.id
FROM Person AS p
INNER JOIN
Account-Subscription AS acsub ON p.account_id=acsub.account_id

MySQL JOIN and COUNT not coherent

I have these tables :
mysql> desc mod_asterisk_booking;
+---------------+------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+---------------+------------------+------+-----+---------+----------------+
| id | int(10) unsigned | NO | PRI | NULL | auto_increment |
| uid | int(10) unsigned | NO | | NULL | |
| server_id | int(10) unsigned | NO | | NULL | |
| date_call | datetime | NO | | NULL | |
| participants | int(10) unsigned | NO | | NULL | |
| ... |
+---------------+------------------+------+-----+---------+----------------+
mysql> desc mod_asterisk_servers;
+-------------------+------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------------------+------------------+------+-----+---------+----------------+
| id | int(10) unsigned | NO | PRI | NULL | auto_increment |
| name | varchar(32) | NO | | NULL | |
| channels_capacity | int(10) unsigned | NO | | NULL | |
| ... |
+-------------------+------------------+------+-----+---------+----------------+
mysql> desc mod_asterisk_server_phones;
+------------------+------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+------------------+------------------+------+-----+---------+----------------+
| id | int(10) unsigned | NO | PRI | NULL | auto_increment |
| server_id | int(10) unsigned | NO | | NULL | |
| phone_number | varchar(15) | NO | | NULL | |
| phone_alias | varchar(15) | NO | | NULL | |
| extension | int(10) unsigned | NO | | NULL | |
| is_toll_free | tinyint(1) | NO | | 0 | |
| is_allow_foreign | tinyint(1) | NO | | 0 | |
+------------------+------------------+------+-----+---------+----------------+
The goal is to fetch a server (from mod_asterisk_servers) that has the enough channels available for a given date interval. This query
SELECT s.*,
s.`channels_capacity` - IFNULL(SUM(b.`participants`), 0) as 'channels_available'
FROM `mod_asterisk_servers` as s
LEFT JOIN `mod_asterisk_booking` as b ON (b.server_id=s.id AND (b.date_call BETWEEN '2011-07-30 15:15:00' AND '2011-07-30 17:15:00'))
GROUP BY s.id
ORDER BY 'channels_available' DESC;
could return something like :
+----+-------------+-----+------------------+--------------------+
| id | name | ... |channels_capacity | channels_available |
+----+-------------+-----+------------------+--------------------+
| 1 | Test server | ... | 150 | 140 |
+----+-------------+-----+------------------+--------------------+
Now, I'd like to add some columns to this query; notably the phone numbers associated with each server found. A phone number may have these combination :
local phone number (is_toll_free=0 AND is_allow_foreign=0)
toll free number, limited to a given region (is_toll_free=1 AND is_allow_foreign=0)
toll free number, allowing an "extended" region (is_toll_free=1 AND is_allow_foreign=1)
I tried this query
SELECT s.*,
s.`channels_capacity` - IFNULL(SUM(b.`participants`), 0) as 'channels_available',
count(p1.phone_number) as 'local_phones',
count(p2.phone_number) as 'toll_free_phones',
count(p3.phone_number) as 'allow_foreign_phones'
FROM `mod_asterisk_servers` as s
LEFT JOIN `mod_asterisk_booking` as b ON (b.server_id=s.id AND (b.date_call BETWEEN '2011-07-30 15:15:00' AND '2011-07-30 17:15:00'))
LEFT JOIN `mod_asterisk_server_phones` as p1 ON (p1.server_id=s.id AND p1.is_toll_free=0 AND p1.is_allow_foreign=0)
LEFT JOIN `mod_asterisk_server_phones` as p2 ON (p2.server_id=s.id AND p2.is_toll_free=1 AND p2.is_allow_foreign=0)
LEFT JOIN `mod_asterisk_server_phones` as p3 ON (p3.server_id=s.id AND p3.is_toll_free=1 AND p3.is_allow_foreign=1)
ORDER BY 'channels_available' DESC;
but it returns
+----+-------------+-----+-------------------+--------------------+--------------+------------------+----------------------+
| id | name | ... | channels_capacity | channels_available | local_phones | toll_free_phones | allow_foreign_phones |
+----+-------------+-----+-------------------+--------------------+--------------+------------------+----------------------+
| 1 | Test server | ... | 150 | 140 | 2 | 2 | 2 |
+----+-------------+-----+-------------------+--------------------+--------------+------------------+----------------------+
even though there are only three numbers for that server :
mysql> select * from mod_asterisk_server_phones where server_id = 1;
+----+-----------+----------------+-------------+-----------+--------------+------------------+
| id | server_id | phone_number | phone_alias | extension | is_toll_free | is_allow_foreign |
+----+-----------+----------------+-------------+-----------+--------------+------------------+
| 1 | 1 | XXX-XXX-XXXX | | XXXX | 0 | 0 |
| 2 | 1 | 1-800-XXX-XXXX | | XXXX | 1 | 0 |
| 3 | 1 | 1-800-XXX-XXXX | | XXXX | 1 | 1 |
+----+-----------+----------------+-------------+-----------+--------------+------------------+
Maybe someone with better understanding of SQL can help me figure out this one?
Thanks!
Try count(DISTINCT p1.phone_number) instead of count(p1.phone_number) (and the same for p2,p3). And don't forget the proper GROUP BY