Laravel query with case and different table subtraction - php

Check my laravel query it's not working... but mysql query works fine.
$data1 = DB::table(DB::raw('(select sum(case when type="debit" then amount else -amount end) from report) - (select sum(amount) from total) as balance' ))
For mysql query please refer sqlfiddle : http://sqlfiddle.com/#!9/2d0343/9
Thanks a lot...

Assuming the type can't be null and has either credit/debit value, you can use aggregation with CASE:
select
sum(case when type='credit' then amount else -amount end)
from report;
Demo
In case the column is nullable or other values are allowed in the column type, you can modify the above like:
select
sum(case when type='credit' then amount
else -amount end)
from report
where type in ('credit', 'debit');
EDIT:
For the latest edit, calculate the difference from one table and subtract the aggregate from other:
select (
select sum(case when type='credit' then amount else -amount end)
from report
) - (select sum(amount) from total);

select sum(case type when 'credit' then amount when 'debit' then -amount else 0 end)
from report

select (sum(case when type='credit' then amount else -amount end)) - (select sum(amount) from total)
from report

Related

Date as column (Create report per day)

I have this query which generates the result that i have wanted.
I just need to make date into a column
SELECT item, date, SUM(quantity)
FROM t
WHERE date between '2015-08-18' and '2015-08-20'
GROUP BY item, date
Here is my SQL FIDDLE
which generates
Result I've wanted
Please can anyone give me at least idea on how to achieve the result I've wanted?
Something like this using conditional Aggregate
To extract the day from date use DAY() function
SELECT item,
SUM(case when day(date) = 18 then quantity else 0 end) as `18`,
SUM(case when day(date) = 19 then quantity else 0 end) as `19`,
SUM(case when day(date) = 20 then quantity else 0 end) as `20`
FROM t
WHERE date between '2015-08-18' and '2015-08-20'
GROUP BY item
SQL FIDDLE DEMO

MySQL fill empty dates

I have been trying to get my head around this for a time now and can't find a solution: I am querying for time-entries with a result like this:
2015-02-10: 13
2015-02-11: 16
2015-02-13: 11
As you can see I am missing two days in the array because there are no entries for these days. My google-fu brought me some solutions for this problem but none seem to work for my specific code:
SELECT
DATE(time_entries.start) AS date,
COUNT(time_entries.id) AS entries,
SUM(CASE WHEN user_id = 4 THEN TIMESTAMPDIFF(MINUTE, start, end) ELSE 0 END) AS me,
SUM(CASE WHEN user_id = 3 THEN TIMESTAMPDIFF(MINUTE, start, end) ELSE 0 END) AS ph
FROM time_entries
LEFT JOIN calendar_table
ON time_entries.start=calendar_table.dt
WHERE start BETWEEN CURRENT_DATE - INTERVAL 1 MONTH AND CURDATE()
GROUP BY date
ORDER BY date
I created the calendar_table with this help: https://www.brianshowalter.com/calendar_tables
Please help!
Best,
Chris
Try with right join. Your query is using your time_entries records to match the calendar table, and finds nothing because they're not there.
By using right join, you'll use calendar_table records first.
SELECT
DATE(time_entries.start) AS date,
COUNT(time_entries.id) AS entries,
SUM(CASE WHEN user_id = 4 THEN TIMESTAMPDIFF(MINUTE, start, end) ELSE 0 END) AS me,
SUM(CASE WHEN user_id = 3 THEN TIMESTAMPDIFF(MINUTE, start, end) ELSE 0 END) AS ph
FROM time_entries
RIGHT JOIN calendar_table
ON time_entries.start=calendar_table.dt
WHERE start BETWEEN CURRENT_DATE - INTERVAL 1 MONTH AND CURDATE()
GROUP BY date
ORDER BY date

SQL number of grouped rows with conditional

I am using the statement below to group results by month to give a total price however I also need to know how many rows have been grouped, but only if the price is above a certain amount.
"SELECT SUM(price) FROM table GROUP BY month";
use SUM with CASE
SELECT SUM(price) totalPrice,
SUM(CASE WHEN price > x THEN 1 ELSE 0 END) totalRows
FROM table
GROUP BY month
where X is the value of price
One option is to use COUNT and CASE:
SELECT SUM(price), COUNT(CASE WHEN Price > 100 THEN 1 END)
FROM table
GROUP BY month
SQL Fiddle Demo

Mysql addition and add them as new column

I want to fetch 2 coulmns count and do their total as a new column.
How can I do this?
i wrote this query, but this is returning wrong total.
SELECT count(case when `status`='1' then 1 else 0 end) AS HOT,
count(case when `status`='5' then 1 end)
AS Special_Case,count(case when 1=1 then 1 end) AS TOTAL
FROM `tbl_customer_conversation` group by
date(`dt_added`),user_id
COUNT will only give the times a record is matched, which in your query will always return 1. Because the values can either be 1 or 0. So count(1) is also 1 and count(0) is also 1.
AS, you want the total number of HOT cases and SPECIAL_CASE you have to use SUM.
SELECT
SUM(case when `status`='1' then 1 else 0 end) AS HOT,
SUM(case when `status`='5' then 1 end) AS Special_Case,
SUM(case when `status` = '1' or `status` = '5' then 1 end) AS TOTAL
FROM `tbl_customer_conversation`
group by date(`dt_added`),user_id

Mysql GROUP BY and COUNT for multiple WHERE clauses

Simplified Table structure:
CREATE TABLE IF NOT EXISTS `hpa` (
`id` bigint(15) NOT NULL auto_increment,
`core` varchar(50) NOT NULL,
`hostname` varchar(50) NOT NULL,
`status` varchar(255) NOT NULL,
`entered_date` int(11) NOT NULL,
`active_date` int(11) NOT NULL,
PRIMARY KEY (`id`),
KEY `hostname` (`hostname`),
KEY `status` (`status`),
KEY `entered_date` (`entered_date`),
KEY `core` (`core`),
KEY `active_date` (`active_date`)
)
For this, I have the following SQL query which simply totals up all records with the defined status.
SELECT core,COUNT(hostname) AS hostname_count, MAX(active_date) AS last_active
FROM `hpa`
WHERE
status != 'OK' AND status != 'Repaired'
GROUP BY core
ORDER BY core
This query has been simplified to remove the INNER JOINS to unrelated data and extra columns that shouldn't affect the question.
MAX(active_date) is the same for all records of a particular day, and should always select the most recent day, or allow an offset from NOW(). (it's a UNIXTIME field)
I want both the count of: (status != 'OK' AND status != 'Repaired')
AND the inverse... count of: (status = 'OK' OR status = 'Repaired')
AND the first answer divided by the second, for 'percentage_dead' (Probably just as fast to do in post processing)
FOR the most recent day or an offset ( - 86400 for yesterday, etc..)
Table contains about 500k records and grows by about 5000 a day so a single SQL query as opposed to looping would be real nice..
I imagine some creative IF's could do this. You expertise is appreciated.
EDIT: I'm open to using a different SQL query for either todays data, or data from an offset.
EDIT: Query works, is fast enough, but I currently can't let the users sort on the percentage column (the one derived from bad and good counts). This is not a show stopper, but I allow them to sort on everything else. The ORDER BY of this:
SELECT h1.core, MAX(h1.entered_date) AS last_active,
SUM(CASE WHEN h1.status IN ('OK', 'Repaired') THEN 1 ELSE 0 END) AS good_host_count,
SUM(CASE WHEN h1.status IN ('OK', 'Repaired') THEN 0 ELSE 1 END) AS bad_host_count
FROM `hpa` h1
LEFT OUTER JOIN `hpa` h2 ON (h1.hostname = h2.hostname AND h1.active_date < h2.active_date)
WHERE h2.hostname IS NULL
GROUP BY h1.core
ORDER BY ( bad_host_count / ( bad_host_count + good_host_count ) ) DESC,h1.core
Gives me:
#1247 - Reference 'bad_host_count' not supported (reference to group function)
EDIT: Solved for a different section. The following works and allows me to ORDER BY percentage_dead
SELECT c.core, c.last_active,
SUM(CASE WHEN d.dead = 1 THEN 0 ELSE 1 END) AS good_host_count,
SUM(CASE WHEN d.dead = 1 THEN 1 ELSE 0 END) AS bad_host_count,
( SUM(CASE WHEN d.dead = 1 THEN 1 ELSE 0 END) * 100/
( (SUM(CASE WHEN d.dead = 1 THEN 0 ELSE 1 END) )+(SUM(CASE WHEN d.dead = 1 THEN 1 ELSE 0 END) ) ) ) AS percentage_dead
FROM `agent_cores` c
LEFT JOIN `dead_agents` d ON c.core = d.core
WHERE d.active = 1
GROUP BY c.core
ORDER BY percentage_dead
If I understand, you want to get a count of the status of OK vs. not OK hostnames, on the date of the last activity. Right? And then that should be grouped by core.
SELECT core, MAX(active_date)
SUM(CASE WHEN status IN ('OK', 'Repaired') THEN 1 ELSE 0 END) AS OK_host_count,
SUM(CASE WHEN status IN ('OK', 'Repaired') THEN 0 ELSE 1 END) AS broken_host_count
FROM `hpa` h1 LEFT OUTER JOIN `hpa` h2
ON (h1.hostname = h2.hostname AND h1.active_date < h2.active_date)
WHERE h2.hostname IS NULL
GROUP BY core
ORDER BY core;
This is a variation of the "greatest-n-per-group" problem that I see a lot in SQL questions on StackOverflow.
First want to choose only the rows that have the latest activity date per hostname, which we can do by doing an outer join for rows with the same hostname and a greater active_date. Where we find no such match, we already have the latest rows for each given hostname.
Then group by core and count the rows by status.
That's the solution for today's date (assuming no row has an active_date in the future). To restrict the result to rows N days ago, you have to restrict both tables.
SELECT core, MAX(active_date)
SUM(CASE WHEN status IN ('OK', 'Repaired') THEN 1 ELSE 0 END) AS OK_host_count,
SUM(CASE WHEN status IN ('OK', 'Repaired') THEN 0 ELSE 1 END) AS broken_host_count
FROM `hpa` h1 LEFT OUTER JOIN `hpa` h2
ON (h1.hostname = h2.hostname AND h1.active_date < h2.active_date
AND h2.active_date <= CURDATE() - INTERVAL 1 DAY)
WHERE h1.active_date <= CURDATE() - INTERVAL 1 DAY AND h2.hostname IS NULL
GROUP BY core
ORDER BY core;
Regarding the ratio between OK and broken hostnames, I'd recommend just calculating that in your PHP code. SQL doesn't allow you to reference column aliases in other select-list expressions, so you'd have to wrap the above as a subquery and that's more complex than it's worth in this case.
I forgot you said you're using a UNIX timestamp. Do something like this:
SELECT core, MAX(active_date)
SUM(CASE WHEN status IN ('OK', 'Repaired') THEN 1 ELSE 0 END) AS OK_host_count,
SUM(CASE WHEN status IN ('OK', 'Repaired') THEN 0 ELSE 1 END) AS broken_host_count
FROM `hpa` h1 LEFT OUTER JOIN `hpa` h2
ON (h1.hostname = h2.hostname AND h1.active_date < h2.active_date
AND h2.active_date <= UNIX_TIMESTAMP() - 86400)
WHERE h1.active_date <= UNIX_TIMESTAMP() - 86400 AND h2.hostname IS NULL
GROUP BY core
ORDER BY core;

Categories