View doesn't show same result as command with subquery on mariadb - mysql

Dears,
I tried to create a view that sumarize transaction per category (row) and months (columns) on one year as this :
SELECT counterpart.id_category as catid, category AS Category, (
SELECT COALESCE(SUM(amount), 0)
FROM transaction
INNER JOIN counterpart
ON transaction.id_counterpart = counterpart.id_counterpart
WHERE YEAR(date) = YEAR(now())
AND MONTH(date) = 1
AND id_category = catid
) AS Jan, [...]
FROM transaction
INNER JOIN counterpart
ON transaction.id_counterpart = counterpart.id_counterpart
INNER JOIN category
ON counterpart.id_category = category.id_category
WHERE transaction.id_user = 2
AND YEAR(date) = YEAR(now())
GROUP BY category
I don't know if it's a good way or not, at least it works as single command but not as view.
On view, the WHERE id_category = catid for subquery doesn't work properly.
Thank you.

I suspect conditional aggregation would be more appropriate and quicker than a lot of sub queries.
for example
SELECT counterpart.id_category as catid, category AS Category,
sum(case when month(date) = 1 then 1 else 0 end) as Jan,
sum(case when month(date) = 2 then 1 else 0 end) as feb,
sum(case when month(date) = 3 then 1 else 0 end) as Mar
FROM transaction
INNER JOIN counterpart
ON transaction.id_counterpart = counterpart.id_counterpart
INNER JOIN category
ON counterpart.id_category = category.id_category
WHERE transaction.id_user = 2
AND YEAR(date) = YEAR(now())
GROUP BY counterpart.id_category,category

Related

How to minimize sql query

I have a booking table in MySQL database where I need to get 3 data.
1) Total Booking
2) Pending Booking ( where is_confirm = 1 )
3) Complete Booking ( where is_confirm = 0 )
Now, I am writing 3 separate query to get this but how can I get it using 1 query?
current query:
$booking = new Admin;
$booking->rowQuery("SELECT count(bid) AS totalBooking FROM booking");
$bookingData = $booking->result->fetch_assoc();
$totalBooking = $bookingData['totalBooking'];
$booking->rowQuery("SELECT bid FROM booking WHERE is_confirm = 1 ");
$completeBooking = $booking->rows;
$booking->rowQuery("SELECT bid FROM booking WHERE is_confirm = 0 ");
$pendingBooking = $booking->rows;
you can use case sql . Try this:
SELECT
COUNT(CASE WHEN is_confirm = 1 THEN 1 END) AS confirmCount,
COUNT(CASE WHEN is_confirm = 0 THEN 1 END) AS noconfirmCount,
COUNT(*) AS total
FROM booking;
SELECT count(bid) AS totalBooking FROM booking
UNION
SELECT bid FROM booking
WHERE is_confirm=1
UNION
SELECT bid FROM booking
WHERE is_confirm=0
Aggregate functions usually skip nulls, including group_concat. If you don't mind explodeing the result string later, you could use case expressions to get the total bookings and coma-delimited strings for the IDs:
SELECT COUNT(bid) AS totalBooking,
GROUP_CONCAT(CASE is_confirm WHEN 1 THEN bid END) AS pendingBookings,
GROUP_CONCAT(CASE is_confirm WHEN 0 THEN bid END) AS completeBookings
FROM booking

mysql sort group by total and name not working

I have Php program that outputs names with the corresponding events attended and the number of times each event was attended over a period of time. As an example of the output
Name | Run | Swim | Bike | Total
John 3 2 5 10
MySQL query look something like this:
$sql = 'SELECT
e.name as Leader,
SUM(CASE WHEN c.catid = 26 THEN 1 ELSE null END) as "Swim",
SUM(CASE WHEN c.catid = 25 THEN 1 ELSE null END) as "Bike",
SUM(CASE WHEN c.catid = 24 THEN 1 ELSE null END) as "Run",
COUNT("Swim"+"Bike"+"Run") as total
FROM
events as e
LEFT JOIN event_categories as c ON c.uid = e.uid
WHERE
(DATE(e.event_start) BETWEEN "'.$from_date.'" and "'.$to_date.'")
GROUP BY Leader WITH ROLLUP;';
This works well, however, if I want to sort my data by "total" in descending order I get no output if I replace the last GROUP BY line with the following:
GROUP BY total DESC, Leader WITH ROLLUP;';
so that I get a listing with names who have the highest totals to the lowest, and people with the same totals get listed in alphabetical order. What am I doing wrong?
As mentioned in the comments, the ORDER BY and ROLLUP can not be used together. It states this here (http://dev.mysql.com/doc/refman/5.0/en/group-by-modifiers.html) about half way down the page. To get around this, you'll have to do the ORDER BY in another query where your original query acts as the subquery:
SELECT *
FROM
(
SELECT
e.name as Leader,
SUM(CASE WHEN c.catid = 26 THEN 1 ELSE null END) as "Swim",
SUM(CASE WHEN c.catid = 25 THEN 1 ELSE null END) as "Bike",
SUM(CASE WHEN c.catid = 24 THEN 1 ELSE null END) as "Run",
COUNT("Swim"+"Bike"+"Run") as total
FROM
events as e
LEFT JOIN event_categories as c ON c.uid = e.uid
WHERE
(DATE(e.event_start) BETWEEN "'.$from_date.'" and "'.$to_date.'")
GROUP BY Leader WITH ROLLUP
) as rolldup
ORDER BY Total DESC
ORIGINAL (WRONG) ANSWER:
You do not put Sorts in a GROUP BY clause. You put them in your ORDER BY clause:
$sql = 'SELECT
e.name as Leader,
SUM(CASE WHEN c.catid = 26 THEN 1 ELSE null END) as "Swim",
SUM(CASE WHEN c.catid = 25 THEN 1 ELSE null END) as "Bike",
SUM(CASE WHEN c.catid = 24 THEN 1 ELSE null END) as "Run",
COUNT("Swim"+"Bike"+"Run") as total
FROM
events as e
LEFT JOIN event_categories as c ON c.uid = e.uid
WHERE
(DATE(e.event_start) BETWEEN "'.$from_date.'" and "'.$to_date.'")
GROUP BY Leader WITH ROLLUP
ORDER BY total DESC;';
You don't want to GROUP BY Total you just want to ORDER BY total.
So the two last lines of your query should be
GROUP BY Leader WITH ROLLUP
ORDER BY total DESC

most recent entry made in table bases on one year interval mysql

Using the following sqlfiddle here How would I find the most recent payment made between the months of 2012-04-1 and 2012-03-31 using the case statement as in the previous queries
I tried this:
max(case when py.pay_date >= STR_TO_DATE(CONCAT(2012, '-04-01'),'%Y-%m-%d') and py.pay_date <= STR_TO_DATE(CONCAT(2012, '-03-31'), '%Y-%m-%d') + interval 1 year then py.amount end) CURRENT_PAY
However the answer I am getting is incorrect, where the actual answer should be:(12, '2012-12-12', 20, 1)
Please Provide me with some assistance, thank you.
Rather than a CASE inside your MAX() aggregate, that condition belongs in the WHERE clause. This joins against a subquery which pulls the most recent payment per person_id by joining on MAX(pay_date), person_id.
SELECT payment.*
FROM
payment
JOIN (
SELECT MAX(pay_date) AS pay_date, person_id
FROM payment
WHERE pay_date BETWEEN '2012-04-01' AND DATE_ADD('2012-03-31', INTERVAL 1 YEAR)
GROUP BY person_id
) maxp ON payment.person_id = maxp.person_id AND payment.pay_date = maxp.pay_date
Here is an updated fiddle with the ids corrected in your table (since a bunch of them were 15). This returns record 18, for 2013-03-28.
Update
After seeing the correct SQL fiddle... To incorporate the results of this query into your existing one, you can LEFT JOIN against it as a subquery on p.id.
select p.name,
v.v_name,
sum(case when Month(py.pay_date) = 4 then py.amount end) april_amount,
(case when max(py.pay_date)and month(py.pay_date)= 4 then py.amount else 0 end) max_pay_april,
sum(case
when Month(py.pay_date) = Month(curdate())
then py.amount end) current_month_amount,
sum(case
when Month(py.pay_date) = Month(curdate())-1
then py.amount end) previous_month_amount,
maxp.pay_date AS last_pay_date,
maxp.amount AS last_pay_amount
from persons p
left join vehicle v
on p.id = v.person_veh
left join payment py
on p.id = py.person_id
/* LEFT JOIN against the subquery: */
left join (
SELECT MAX(pay_date) AS pay_date, amount, person_id
FROM payment
WHERE pay_date BETWEEN '2012-04-01' AND DATE_ADD('2012-03-31', INTERVAL 1 YEAR)
GROUP BY person_id, amount
) maxp ON maxp.person_id = p.id
group by p.name,
v.v_name

Finding the Most current entry for a month using mysql

I am having a mysql problem I am trying to find both the most current payment value, and, for a particular month (in this query I'm using April). Link to the sqlfillde is here
(case when max(py.pay_date)and month(py.pay_date)= 4 then amount else 0 end) max_pay_april,
This is what I have but it doesn't seem to be working. The most current payment value is: (5, '2012-04-20', 90,) therefore it would be 90 I would really appreciate some help please.
How about this:
select p.name,
v.v_name,
sum(case when Month(py.pay_date) = 4 then amount end) april_amount,
max(case
when month(py.pay_date)= 4
and py.pay_date = (select max(pay_date)
from payment
where month(pay_date) =4 )
then amount else 0 end) max_pay_april,
sum(case
when Month(py.pay_date) = Month(curdate())
then amount end) current_month_amount,
sum(case
when Month(py.pay_date) = Month(curdate())-1
then amount end) previous_month_amount
from persons p
left join vehicle v
on p.id = v.person_veh
left join payment py
on p.id = py.person_id
group by p.name,
v.v_name
see SQL Fiddle with demo

MySQL select subqueries

This is what I have at the moment.
$db =& JFactory::getDBO();
$query = $db->getQuery(true);
$query->select('`#__catalog_commit`.`id` as id, `#__catalog_commit`.`date` as date, COUNT(`#__catalog_commit_message`.`commit_id`) as count,
(SELECT COUNT(`#__catalog_commit_message`.`type`) as count_notice FROM `#__catalog_commit_message` WHERE `#__catalog_commit_message`.`type` = 1 GROUP BY `#__catalog_commit_message`.`type`) as count_notice,
(SELECT COUNT(`#__catalog_commit_message`.`type`) as count_warning FROM `#__catalog_commit_message` WHERE `#__catalog_commit_message`.`type` = 2 GROUP BY `#__catalog_commit_message`.`type`) as count_warning,
(SELECT COUNT(`#__catalog_commit_message`.`type`) as count_error FROM `#__catalog_commit_message` WHERE `#__catalog_commit_message`.`type` = 3 GROUP BY `#__catalog_commit_message`.`type`) as count_error');
$query->from('#__catalog_commit_message');
$query->leftjoin('`#__catalog_commit` ON `#__catalog_commit`.`id` = `#__catalog_commit_message`.`commit_id`');
$query->group('`#__catalog_commit_message`.`commit_id`');
$query->order('`#__catalog_commit`.`id` DESC');
What I have is 2 tables with the following structures:
catalog_commit
==============
id
date
catalog_commit_message
======================
id
commit_id
type
message
Basically I want to have the count of each different types of messages per group items. In what I have it actually select every rows (Which is normal) but I'm looking for a way (nicier if possible) to have the count per messages type within the query.
EDIT: Just wanted to add that it's a JModelList.
From what I gather, this should be your query:
SELECT c.id
,c.date
,count(cm.commit_id) as ct_total
,sum(CASE WHEN cm.type = 1 THEN 1 ELSE 0 END) AS count_notice
,sum(CASE WHEN cm.type = 2 THEN 1 ELSE 0 END) AS count_warning
,sum(CASE WHEN cm.type = 3 THEN 1 ELSE 0 END) AS count_error
FROM catalog_commit c
LEFT JOIN catalog_commit_message cm ON cm.commit_id = c.id
GROUP BY c.id, c.date
ORDER BY c.id DESC
You had the order of your tables reversed in the LEFT JOIN. Also, you had weird subqueries in the SELECT list.