Mysql select query, splitting column data conditionally into 2 new columns - mysql

I have a table called credit_log and the columns are
user_id | amount
The amount can be positive or negative. Positive means credits bought, negative means credits spent.
So, I want to have a query which returns
user_id | Bought | Spent
essentially , i want to sum up positive amount values in to Bought and sum up negative amount in to Spent and I want to group by the user_id
Currently I have a query like this
select user_id,sum(amount) from credit_log group by user_id;
but it sums up both positive and negative values. How can I write a query to separate them?

Some conditional statements inside the query should work nicely:
SELECT
user_id,
SUM(IF(amount > 0, amount, 0)) bought,
SUM(IF(amount < 0, amount, 0)) spent
FROM credit_log
GROUP BY user_id;

select user_id, sum(if(amount>0,amount,0)) bought, sum(if(amount<0,amount,0)) spent
from web_user_credits group by user_id;

I'm not 100% the syntax is the same in mysql... but it looks like it:
select
user_id
,case when amount > 0 then amount else 0 end as bought
,case when amount < 0 then amount else 0 end as spent
from
credit_log
And you can go on to simply place sum() around the case statements (include the end but not as).

check this :
select user_id , sum(if(amount< 0 ,0 ,amount )) as spent,
sum(if(amount> 0 ,0 ,amount )) as bought
from credit_log group by user_id

Related

Mysql - most efficient way to retrieve data based on multiple selects and wheres

I'm having trouble finding the most efficient way of retrieving various different sumed values from a Mysql table.
Let's say I've got 4 columns - userid, amount, paid, referral.
I'd like to retrieve the following based on a user id:
1 - the sum of amount that is paid (marked as 1)
2 - the sum of amount that is unpaid (marked as 0)
3 - the sum of amount that is paid and referral (marked as 1 on both paid and referral columns)
4 - the sum of amount that unpaid and referral (marked as 0 on paid and 1 on referral columns)
I've tried an embedded select statement like this:
SELECT (
SELECT sum(payout)
FROM table1
WHERE ispaid = 0 and userid = '100'
) AS unpaid
(
SELECT sum(payout)
FROM table1
WHERE ispaid = 1 and userid = '100'
) AS paid,
(
SELECT sum(payout)
FROM table1
WHERE ispaid = 0 and isreferral = 1 and userid = '100'
) AS refpending,
(
SELECT sum(payout)
FROM table1
WHERE ispaid = 1 and isreferral = 1 and userid = '100'
) AS refpaid
This works, but its slow (or at least feels like it could be quicker) on my server, around 1.5 seconds.
I'm sure there is a better way of doing this with a group statement but can't get my head around it!
Any help is much appreciated.
Thanks
You can use conditional expressions inside SUM():
SELECT
SUM(CASE WHEN ispaid=0 THEN payout END) AS unpaid,
SUM(CASE WHEN ispaid=1 THEN payout END) AS paid,
SUM(CASE WHEN ispaid=0 AND isreferral=1 THEN payout END) AS refpending,
SUM(CASE WHEN ispaid=0 AND isreferral=1 THEN payout END) AS refpaid
FROM table1
WHERE userid = '100'
If a given row is not matched by any CASE...WHEN clause, then the value of the expression is NULL, and SUM() ignores NULLs. You could also have an ELSE 0 clause in there if you want to be more explicit, since SUM() will not be increased by a 0.
Also make sure you have an index on userid in this table to select only the rows you need.

MySql - Pulling two different sums from the same column

I am working on a game with a MySql database. In the game we have a system where characters have a debt that can be paid. We track each debt singularly and flag whether its paid or not with a Boolean 0,1.
I am trying to understand how in a single query I can sum the total paid amount as well as the total owed amount from a single character ID. The tables are
charid, amount, paid (the boolean)
Currently if I just want to find out how much they owe I simply place
SELECT sum(amount) FROM debts WHERE paid='0';
So how would I modify this to create a resulting column for both paid='0' and paid='1' ?
Thanks all.
Use conditional aggregation. Since the paid flag holds 0/1 values, you can just do:
select
sum(paid * amount) amount_paid,
sum( (1 - paid) * amount) amount_owed
from debts
you can use conditional aggregation using select case.
SELECT
sum(case when paid = 0 then amount else 0 end) as not_paid
,sum(case when paid > 0 then amount else 0 end) as paid
FROM debts
SELECT user, paid, SUM(amount) total FROM debts GROUP BY user, paid

Count and group by number of records in select query result set

I have a table with emp_id, income, etc.
I wish to get number of records for a query like
select * from table_name where income <= 500;
There will be at least 3 such income groups - which will b given at report generation time.
Further I wish to get all 3 Counts - and group the results by the count of their respective income group - all this in a single query.
What is the easiest way to do this?
Can you try this ,if this doesn't suite your need you may need to write a custom stored procedure
SELECT
sum((income <= 500)) as range1,
sum((income <= 1000)) as range2
FROM table_name
sample fiddle
You can use a CASE expression to create your categories, and then a GROUP BY to summarize the categories.
SELECT COUNT(*) AS num,
CASE WHEN income IS NULL THEN 'missing'
WHEN income <= 0 THEN '0'
WHEN income <= 500 THEN '1 - 500'
WHEN income <= 1000 THEN '501-1000'
ELSE '> 1000'
END AS category
FROM table_name
GROUP BY category WITH ROLLUP
Including the WITH ROLLUP clause will give you an overall count as well as the count of each category.

SQL aggregation query for SUM, but only allow positive sums (otherwise 0)

I want to query an orders table and show the customer id and the total of all his orders, however the orders can have positive or negative totals.
select customer_id, SUM(order_total) from orders group by customer_id;
Now my question - how can I achieve the following in one sql query:
If the total sum is positive, I want to display it as is; if the total sum is negative, I just want to display 0 instead the actual amount.
What I am looking for is a function that can handle this, similar to the IFNULL function (IFNULL(SUM(order_total),0)), but instead of checking for null, it should check for a negative result.
Pseudo code:
IFNEGATIVE(SUM(order_total),0)
Is there a simple way in standard sql (or specifically in Mysql 5.5, would also be ok).
SELECT customer_id,
CASE
WHEN SUM(order_total) < 0 THEN 0
ELSE SUM(order_total)
END
FROM orders
GROUP BY customer_id;
Check your execution plan, but the 2 SUMs will probably be optimized to a single SUM under the hood.
Try with:
select customer_id, GREATEST( SUM(order_total),0) from orders group by customer_id;
Not tested, but something like this should do it:
SELECT customer_id , IF( SUM(order_total) > 0, SUM(order_total), 0) AS sum FROM orders GROUP BY customer_id
Could you not use a CASE statement?
Something like:
CASE WHEN [Field] < 0 THEN 0
Or did I miss something?
if i understand its only wrap it with GREATEST
SELECT customer_id, GREATEST(0,SUM(order_total))
FROM orders GROUP BY customer_id;
look on the link
select Id,case when (sum(amount)<0) then 0 else sum(amount) end from tblsum group by Id
You can also try;
select
(sum(fld) + abs(sum(fld))) / 2
from tbl
To only display positive Use HAVING thus:
select customer_id, SUM(order_total) from orders group by customer_id HAVING SUM(order_total) > 0;
Otherwise use case as listed elsewhere here

mysql: conditional statement problem, greather then

When I run this query It works
SELECT sum( amount ) AS balance FROM balance WHERE amount >= 100
but when I want to filter for the userid it returns NULL
SELECT sum( amount ) AS balance FROM balance WHERE amount >= 100 AND userid=4
It will return NULL if there are no rows. If you want zero instead then use this:
SELECT IFNULL(SUM(amount), 0) AS balance
FROM balance
WHERE amount >= 100 AND userid = 4
If you believe that the answer should be something other than 0 or NULL then I suggest you run this query to double-check that at least one row is returned and that the data is correct:
SELECT *
FROM balance
WHERE amount >= 100 AND userid = 4