I have following table.
---+---------------+-------------+--------+
id | department_id | created | amount |
---+---------------+-------------+--------+
1 | 0 | 2016-05-05 | 500 |
2 | 2 | 2016-05-05 | 100 |
3 | 1 | 2016-05-05 | 160 |
4 | 2 | 2016-05-05 | 260 |
5 | 1 | 2016-05-04 | 100 |
6 | 0 | 2016-05-04 | 150 |
7 | 1 | 2016-05-04 | 160 |
8 | 2 | 2016-05-04 | 160 |
---+---------------+-------------+--------+
I want to generate report to show how much collection is there on particular day in particular department & need to show like below table:
Date | 0 | 1 | 2 |
2016-05-05 | 500 | 160 | 360 |
2016-05-04 | 150 | 260 | 160 |
I am using cakephp. If I use GROUP BY created it works and if I use GROUP BY department_id it works. But I need both GROUP BY to generate the required report.
I also tried generating the from to date array using this. and then tried running GROUP BY created on each date using following CakePHP query:
//$ar = date array
foreach ($ar as $k) {
$this->Transaction->find('all',array('conditions'=>array('Transaction.created'=>$k),'fields'=>array('SUM(Transaction.amount) AS s','Transaction.department_id'),'group'=>array('Transaction.department_id')));
}
But it seems like slow solution to me if date range is long. Is there any best way to do it in single query.
Please help me sorting this problem.
Variations of this question are asked and answered endlessly. A typical solution goes something like this...
SELECT created date
, SUM(CASE WHEN department_id = 0 THEN amount END) dept0
, SUM(CASE WHEN department_id = 1 THEN amount END) dept1
, SUM(CASE WHEN department_id = 2 THEN amount END) dept2
FROM my_table
GROUP
BY date;
simple group by two columns department_id and created - and sum(amount) function to calculate total for each group.
$report_rows = $this->{{Model_NAME}}->find('all', array(
'fields' => array('department_id', 'created', 'sum(amount)'),
'group' => 'department_id, created'
));
and then you can show this report on view
$dates = Set::extract('/{{Model_NAME}}/created', $report_rows);
$departments = Set::extract('/{{Model_NAME}}/department_id', $report_rows);
Now you can make dates in columns and departments as row title. Hope this help, it's not complied, may contain some bugs but logic will work well.
Related
Hello and sorry if this questions isn't good formatted, here's my problem:
for simplicity let's say i have a table with products
-----------------------
| id| age |price|name|
----------------------|
| 0 | 0 | 50 | x |
| 1 | 1 | 51 | x |
| 2 | 2 | 52 | x |
| 3 | 3 | 53 | x |
| 4 | 4 | 54 | x |
| 5 | 5 | 55 | x |
| 6 | 6 | 56 | x |
| 7 | 7 | 57 | x |
| 8 | 8 | 58 | x |
-----------------------
I want to get the price for all products of age 0 and 1 with
select price from products where name='x' and(age=0 or age=1)
and it works returning two rows but when the age is the same logically it returns one row and that's my problem how to get it to return again all the rows i want or if something other is wrong with my logic, thank you in advance
One way to achieve this is to build a derived table of the ages that you want to query against and then JOIN that to the products table. Note that you need to use UNION ALL in the derived table to maintain duplicates. Additional values can be searched by adding another UNION ALL SELECT n to the derived table for each value:
SELECT p.price
FROM (SELECT 0 AS age
UNION ALL
SELECT 0) ages
JOIN products p ON p.age = ages.age
WHERE p.name = 'x'
Output:
price
50
50
Demo on dbfiddle
This question already has answers here:
SQL Group By and min (MySQL)
(3 answers)
Closed 6 years ago.
[Foreword for the compulsives -1] I know this question has been answered, at least, a billion times, but the problem is that I can't model those answers to what I wanna obtain. I'm not an SQL expert, that's sure; I'm confident just with the classical commands like SELECT, UPDATE, DELETE, ecc. so I'm gonna thank anyone who will like to help me.
Said that, let's suppose I have a table like this one:
|----|--------|------------|----|----------|---------|---------|------|
| id | code | category | mq | weight | weave | price | show |
|----|--------|------------|----|----------|---------|---------|------|
| 1 | DT450R | carbon | 1 | 450 | plain | 90 | 1 |
| 2 | DT450R | carbon | 2 | 450 | plain | 40 | 1 |
| 3 | DT450R | carbon | 5 | 450 | plain | 75 | 1 |
| 4 | ZX300R | carbon | 1 | 300 | plain | 12 | 0 |
| 5 | ZX300R | carbon | 15 | 300 | plain | 128 | 1 |
| 6 | ZX300R | carbon | 30 | 300 | plain | 92 | 1 |
| 7 | PP120Q | carbon | 3 | 120 | twill | 28 | 1 |
| 8 | PP120Q | carbon | 7 | 120 | twill | 65 | 1 |
| 9 | PP120Q | carbon | 9 | 120 | twill | 49 | 1 |
What I would like my query to do is to select, for each code, just the row with the minimum price:
| 2 | DT450R | carbon | 2 | 450 | plain | 40 | 1 |
| 4 | ZX300R | carbon | 1 | 300 | plain | 12 | 0 |
| 7 | PP120Q | carbon | 3 | 120 | twill | 28 | 1 |
First attempt (based on the explanation of MIN() given in MySQL documentation or, at least, on what I understood of it):
$sql = 'SELECT code, weight, weave, MIN(price)
FROM products
WHERE category="carbon" AND show="1"
GROUP BY code
ORDER BY weight ASC';
Second attempt (based on this answer here on SO):
$sql = 'SELECT a.code, a.weight, a.price, a.weave
FROM products a
INNER JOIN
(
SELECT code, weight, MIN(price) AS minprice, weave
FROM products
GROUP BY code
)
b ON a.code = b.code AND a.weave = b.weave AND a.price = b.minprice AND AND a.weight = b.weight
WHERE category="carbon" AND show="1"
ORDER BY a.weight ASC';
Third attempt (based on this other answer here on SO):
$sql = 'SELECT code, weight, weave, price
FROM products
INNER JOIN
(
SELECT MIN(price) price, code, weight, weave
FROM products
GROUP BY code
)
AS MIN ON MIN.code = products.code AND MIN.weight = products.weight AND MIN.weave = products.weave
WHERE category="carbon" AND show="1"
ORDER BY a.weight ASC';
It's probably useless say that none of these attempts produced the expected result; just the third method outputs something while the others two return 0 matches. I understood that in the 2nd and 3rd methods I'm nesting a query into a query but I can't figure out why they don't work.
You're close with your second attempt. But the only columns you should be joining on are code and price. weight and weave then come from the row that's selected by this join condition.
SELECT a.code, a.weight, a.price, a.weave
FROM products a
INNER JOIN
(
SELECT code, MIN(price) AS minprice
FROM products
GROUP BY code
)
b ON a.code = b.code AND a.price = b.minprice
WHERE category="carbon" AND show="1"
ORDER BY a.weight ASC
This is the same as the answers in the questions you linked to. None of them suggest adding other columns to the ON clause, so I'm not sure where that came from.
i´ve been hitting rock bottom recently.
What i´m currently trying to do is "sorting" a selection of database entries by date and if the date has passed and value X has not changed then append it ontop of the list and if the value has changed at bottom.
Maybe its a bit better to make some sort of graphic explaining my problem.
Entry | "date" | X
1 | 10.07 | 0
1 | 11.07 | 1
1 | 12.07 | 1
1 | 13.07 | 1
1 | 14.07 | 1
1 | 15.07 | 1
1 | 16.07 | 1
1 | 17.07 | 1
1 | 18.07 | 0
1 | 19.07 | 1
This should transform to
Entry | "date" | X
1 | 19.07 | 1
1 | 17.07 | 1
1 | 16.07 | 1
1 | 15.07 | 1
1 | 14.07 | 1
1 | 13.07 | 1
1 | 12.07 | 1
1 | 11.07 | 1
1 | 18.07 | 0
1 | 10.07 | 0
Is that even possible to do with "pure" mysql ?
I´ve been trying to get it sort of working by "sorting" by date, but thats not what i wanted to accomplish in the end.
SELECT * FROM table_entries ORDER BY start_date ASC LIMIT 25
Have a great day
If I got it right you'd like to sort your rows by X value (having ones on top) and then sort them by date.
You can achieve it by using ORDER BY X,start_date
in your query. You can specify ASC or DESC after X and start_date to obtain the desired effect
Your query wuld become something like this:
SELECT * FROM table_entries ORDER BY X DESC, start_date ASC LIMIT 25
Make order by both 'x' and 'date' field. So all the records will be sorted by 'x' first and then by date.
SELECT * FROM table_entries ORDER BY x DESC, start_date DESC LIMIT 25
I have the following mysql query:
SELECT sub_nine, sum(sub.sub_low_nett) AS points, sub_pid FROM
(SELECT c.cn_nine as sub_nine, min(rh.rh_nett) AS sub_low_nett, p.id AS sub_pid
FROM round r, round_hole rh, player p, course_nine c, course_hole ch
WHERE r.r_id = rh.rh_rid
AND p.id = r.r_pid
AND c.cn_nine = r.r_nine
AND ch.ch_nine = c.cn_nine
AND rh.rh_hid = ch.ch_no
GROUP BY p.id, c.cn_nine, ch.ch_no
) AS sub
GROUP BY sub_pid, sub_nine
ORDER BY sub_pid
Which returns the following result:
|sub_nine|points|sub_pid
| 1 | 2 | 1
| 2 | 17 | 1
| 3 | NULL | 1
| 1 | NULL | 2
| 2 | NULL | 2
| 3 | NULL | 2
| 1 | NULL | 3
| 2 | 26 | 3
| 3 | 4 | 3
| 1 | 26 | 5
| 2 | 36 | 5
The result set has been looped into a multi-dimensional array, using the fetch_assoc() function.
I need to display each of the points totals per player as well as the total of those points (distinctly / uniquely) for each player in a table
I think I need to loop through the initial multi-dimensional array, and probably place into a new array that has been pivoted around the columns rather than rows, but stuck as to how to do this.
The initial query is sorted by pid, so I know that as you loop through the array, the rows can be cumulatively totaled.
I also need the final array to be sorted by the new total value per player as well.
pid | score1 | score2| score3 | total
the data structure is laid out here:
Gold DB ERD Diagram
ok, first of all sorry for the title, but I could not work out a better one :(
This is the problem:
I have two tables, properties and properties_rooms, linked each other by the propery ID.
properties table:
+---------------+------------+
| id_properties | pr_title |
+---------------+------------+
| 1 | test |
| 2 | dummy |
+---------------+------------+
properties_rooms table:
+---------------+-------------------+--------------+----------+
| id_prop_rooms | pro_id_properties | pro_id_rooms | pro_size |
+---------------+-------------------+--------------+----------+
| 1 | 1 | 4 | 5.00 |
| 2 | 1 | 18 | 17.00 |
| 3 | 2 | 6 | 12.00 |
| 4 | 2 | 24 | 11.00 |
| 5 | 1 | 4 | 10.00 |
| 6 | 1 | 6 | 10.00 |
| 7 | 1 | 6 | 12.00 |
+---------------+-------------------+--------------+----------+
I'm working on an advanced search, where users can search for a property that has more than a rooms of the same type (ie two bedrooms, 3 bathrooms and so on).
Sadly, I find myself stuck on this, since I can't "filter" the same dataset with multiple clause; if i have to filter only one there will be no problems, since I can use an HAVING clause.
I worked out this select:
SELECT id_properties, pro_id_rooms, COUNT(*) as total,
IF ((pro_id_rooms = 4 AND COUNT(*) >= 2) OR (pro_id_rooms = 6 AND COUNT(*) >= 2), 1, 0) as flag
FROM `properties`
INNER JOIN properties_rooms ON id_properties = pro_id_properties
WHERE id_properties IN (4,10)
GROUP BY id_properties, pro_id_rooms
ORDER BY id_properties
Inside the IN clause there are the properties that I know they have at least one of requested rooms. They came from a previous query since I have to work with GROUP BY and HAVING.
The IF part inside the select is built at run-time, since I get the information from the request.
This is the result:
+---------------+--------------+-------+------+
| id_properties | pro_id_rooms | total | flag |
+---------------+--------------+-------+------+
| 1 | 4 | 2 | 1 |
| 1 | 6 | 2 | 1 |
| 1 | 18 | 1 | 0 |
| 2 | 6 | 1 | 0 |
| 2 | 24 | 1 | 0 |
+---------------+--------------+-------+------+
I think it could work, I only need to add an HAVING flag > 0 and I'm done.
My question is, is there anything better?
Tables aren't very large: properties one could be something like 1k, rooms one about 10k.
I'm afraid that if the user puts too much rooms, the query would become an enormous IF statement...
SELECT id_properties, SUM(pro_id_rooms = 4) AS bedrooms, SUM(pro_id_rooms = 6) AS bathrooms
FROM `properties`
INNER JOIN properties_rooms ON id_properties = pro_id_properties
WHERE id_properties IN (4,10)
GROUP BY id_properties
HAVING bedrooms >= 3 AND bathrooms >= 2
Changes
SUM(pro_id_rooms = 4) AS bedrooms, SUM(pro_id_rooms = 6) AS bathrooms
For each checkbox the user has selected, you need a SUM(pro_id_rooms = x) AS nrofx in your WHERE.
HAVING bedrooms >= 3 AND bathrooms >= 2
This is where you check the number of a particular room.