mysql get difference instead of SUM - mysql

I have the following query :
SELECT SUM(P_QTY)
FROM rankhistory
WHERE P_ID= '1'
AND RH_DATE>=1438556400
AND RH_DATE<1438642800
The above query returns 268
The result set contains two elements of P_QTY which are 160 and 108
Now what I want is be able to receive the difference instead of the sum, so what I want my query to return is 52, how can I achieve that through sql query?
Please note that the subquery can return more than one result, and the intended is get the total change. For example if query returns 168 160 150, the result should be 18.

There's no aggregate function for difference, but since you know exactly which rows to use, you can select each value as its own subquery, then subtract the two columns from one another in a single select statement.
SELECT a.op, b.op, a.op - b.op as diff
FROM (SELECT 10 as op) a
JOIN (SELECT 8 as op) b
Expressed in accordance with your schema, it would probably look like this:
SELECT a.op, b.op, a.op - b.op as diff
FROM (SELECT P_QTY as op FROM rankhistory WHERE P_QTY = 160) a
JOIN (SELECT P_QTY as op FROM rankhistory WHERE P_QTY = 108) b
To use this approach regularly in an application, however, you'll want to handle it based on ID's or something else easily selectable and meaningful.
It sounds like you want something else, though. Perhaps you're interested in the difference between max and min during a date range?
SELECT MAX(P_QTY) - MIN(P_QTY) as diff
FROM rankhistory
WHERE rh_date BETWEEN '1438556400' AND '1438642800'

Related

Trying to use a select query after two with statements

I plan to make two with queries that make two temporary tables, one which gives the sum of the remaining loan payments, and one that gives the sum of all the transactions in the table. I've tested the two with statements and they work by themselves, however trying to perform a select query with them only seems to return errors.
WITH RemainingLoans AS(SELECT SUM(TIMESTAMPDIFF(MONTH, l.NextPayment, l.FullPaymentConfirmed) * l.MonthlyPaymentRate) AS RemainingPayments FROM loans AS l);
WITH CurrentBalances AS(SELECT SUM(t.amount) AS allBalances FROM transactions AS t);
SELECT l.RemainingPayments - b.allBalances AS TotalOutstandings FROM RemainingLoans AS l, CurrentBalances AS b;
The first with is called RemainingLoans with one attribute RemainingPayments, and the second with is called CurrentBalances with one attribute allBalances. To my knowledge these should work like tables which is why I attempted my select clause on the third line, however I am currently getting syntax errors. Is there a correct way to format my select statement?
This should be a single statement, not multiple statements.
The fiddle
WITH list elements are separated by a comma. There's only one WITH keyword at the beginning of the list.
The semicolon goes at the end of the entire statement, not after the WITH list elements.
Here's the adjusted statement:
WITH RemainingLoans AS (
SELECT SUM(TIMESTAMPDIFF(MONTH, l.NextPayment, l.FullPaymentConfirmed) * l.MonthlyPaymentRate) AS RemainingPayments
FROM loans AS l
)
, CurrentBalances AS (
SELECT SUM(t.amount) AS allBalances
FROM transactions AS t
)
SELECT l.RemainingPayments - b.allBalances AS TotalOutstandings
FROM RemainingLoans AS l
, CurrentBalances AS b
;

The query gives single row query returns more than one row

I'm trying to show staff_code, staff_name and dept_name for those who have taken one book.
Here's my query:
SELECT SM.STAFF_CODE,SM.STAFF_NAME,DM.DEPT_NAME,BT.BOOK_CODE
FROM STAFF_MASTER SM,DEPARTMENT_MASTER DM,BOOK_TRANSACTIONS BT
WHERE SM.DEPT_CODE =DM.DEPT_CODE
AND SM.STAFF_CODE = (
SELECT STAFF_CODE
FROM BOOK_TRANSACTIONS
HAVING COUNT(*) > 1
GROUP BY STAFF_CODE)
It gives the error:
single-row subquery returns more than one row.
How to solve this?
Change = to IN:
WHERE SM.STAFF_CODE IN (SELECT ...)
Because the select returns multiple values, using equals won't work, but IN returns true if any of the values in a list match. The list can be a hard-coded CSV list, or a select with one column like your query is.
That will fix the error, but you also need to remove BOOK_TRANSACTIONS from the table list and remove BOOK_CODE from the select list.
After making these changes, your query would look like this:
SELECT SM.STAFF_CODE,SM.STAFF_NAME,DM.DEPT_NAME
FROM STAFF_MASTER SM,DEPARTMENT_MASTER DM
WHERE SM.DEPT_CODE =DM.DEPT_CODE
AND SM.STAFF_CODE IN (
SELECT STAFF_CODE
FROM BOOK_TRANSACTIONS
HAVING COUNT(*) > 1
GROUP BY STAFF_CODE)
I recommend learning the modern (now over 25 year old) JOIN syntax.

How to CAST an Alias

I am trying to calculate a due amount summing and grouping more amounts in table i_payment_history comparing then the result with the total "to_be_payed" amount saved in table pt_bookings. All involved fields are decimal(8,2), i have tryied with Cast becouse without is not working eather. The value "Due" is just the result of 'to_be_payed'-'payed'
so the first value in column "Due" should be 755,10-200,00=535,10 .
Why is "Due" calculating a wrong value? Txs !
SELECT i_payments_history.booking_id, Cast(SUM(amount)AS DECIMAL(8,2)) as payed, pt_bookings.booking_total, pt_bookings.booking_ref_no, (pt_bookings.booking_total - payed) as due
FROM `i_payments_history`
JOIN pt_bookings
on pt_bookings.booking_id= i_payments_history.booking_id
GROUP BY booking_id
see in below pic what the query is returning
Repeat the expression:
SELECT ph.booking_id, Cast(SUM(ph.amount) AS DECIMAL(8,2)) as payed, b.booking_total, b.booking_ref_no,
(b.booking_total - SUM(ph.amount)) as due
FROM `i_payments_history` ph JOIN
pt_bookings b
on b.booking_id = ph.booking_id
GROUP BY b.booking_id;
An alias cannot be used in the same select where it is defined. One alternative is to use a subquery; another is to repeat the expression. Your query did not return an error because one of your tables must have a column named payed.

mysql SELECT JOIN and GROUP BY

Here is my query:
SELECT v2.mac, v2.userag_hash, v2.area, count(*), count(distinct v2.video_id)
FROM video v2 JOIN (
SELECT distinct v.mac, v.userag_hash
from video v
WHERE v.date_pl >= '2012-01-30 00:00' AND
v.date_pl <= '2012-02-05 23:55'
ORDER BY rand() LIMIT 50
) table2
ON v2.mac = table2.mac AND
v2.userag_hash = table2.userag_hash AND
v2.date_pl >= '2012-01-30 00:00' AND
v2.date_pl <= '2012-02-05 23:55'
GROUP BY v2.mac, v2.userag_hash
I have one table "video" in the database, it contains several thousand users' data, now I want to randomly select 50 users and calculate based on the selected rows, (each user is identified by unique combination of ), this query's result is:
usermac1, userag_hash1, area1, 10, 5
usermac2, userag_hash2, area2, 20, 8
...
But if I don't use "GROUP BY" in the end of the query, then it will return only one row:
usermac, userag_hash, areax, 1500, 700 (don't know what this row stands for)
I am wondering if the "1500, 700" is the sum of the last two columns of the previous results. like 1500 = 10+20+... 700 = 5+8+...
Based on the fact that you have only one aggregate function (count) and used on 2 columns, and you can run it without GROUP BY at all, you must be using the non-standards compliant MySQL.
SELECT v2.mac, v2.userag_hash, v2.area, count(*), count(distinct v2.video_id)
...
Whatever your data is, MySQL will return one row when you use aggregate functions, which is:
<undefined value>, <undefined value>, count of all rows, count of rows where v2.video_id is distinct (and probably non null).
So I think you have 1500 rows, and 700 distinct values of v2.video_id, or 700 non-null distinct values. To test this null idea, try:
count(distinct IFNULL(v2.video_id,'nullvaluehere'))
which will convert nulls to non-null so they will be included.
The "undefined values" could be the first row, last row, first where something is non null, first in an index, first in some cache, etc. There is no definition of what should happen when you write an invalid query.
Every SQL database I'm aware of other than MySQL will give you an error message and not even run the query. For the query to be valid, it must have all non-aggregated columns in the group by. eg. mac and userag_hash must both be in group by.

Get count of complex query

I would like to count the total number of rows returned by the following query:
SELECT table1.*, COUNT(table2.fk) * (100/18) AS 'number'
FROM table1 INNER JOIN table2 ON table1.pk = table2.fk
WHERE table1.Street LIKE '$Street%'
AND table1.City LIKE '$City%'
AND table1.Zip LIKE '%$Zip'
AND table1.DOBY LIKE '%$DOBY'
AND table1.DOBM LIKE '%$DOBM'
AND table1.DOBD LIKE '%$DOBD'
AND table1.Gender LIKE '$gender%'
AND table2.year>= 2004
AND table2.type IN ('AA', 'AB', 'AC')
GROUP BY table2.fk
HAVING (COUNT(table2.fk) * (100/18)) >= '$activity'
ORDER BY DOBY, DOBM, DOBD ASC
The query counts the number or times the primary key of table1 occurs as the foreign key of table2, and calculates a percentage ('number') based on a fixed amount. It works well enough, but I'm having trouble getting the total amount of records found for my pagination script.
I would appreciate it if anyone can offer some suggestions or solutions.
u can do SQL_CALC_FOUND_ROWS (google for exact syntax)
And then use SELECT FOUND_ROWS() AS total
Going with what Itay Moav says, a programming language should have a function for the found_rows function. As per the function documentation, it returns the number of rows of a SELECT statement with a LIMIT keyword if the LIMIT keyword wasn't there.
If it doesn't, you can just make another SELECT query to the database: SELECT FOUND_ROWS();. It will return the same information.