SQL/MySQL SELECT and average over certain values - mysql

I have to work with an analysis tool that measures the Web Service calls to a server per hour. These measurments are inserted in a database. The following is a snippet of such a measurement:
mysql> SELECT * FROM sample s LIMIT 4;
+---------+------+-------+
| service | hour | calls |
+---------+------+-------+
| WS04 | 04 | 24 |
| WS12 | 11 | 89 |
| WSI64 | 03 | 35 |
| WSX52 | 01 | 25 |
+---------+------+-------+
4 rows in set (0.00 sec)
As the end result I would like to know the sum of all web services completions per hour of day. Obviously, this can be easily done with SUM() and GROUP BY:
mysql> SELECT hour, SUM(calls) FROM sample s GROUP BY hour;
+------+------------+
| hour | SUM(calls) |
+------+------------+
| 00 | 634 |
| 01 | 642 |
| 02 | 633 |
| 03 | 624 |
| 04 | 420 |
| 05 | 479 |
| 06 | 428 |
| 07 | 424 |
| 08 | 473 |
| 09 | 434 |
| 10 | 485 |
| 11 | 567 |
| 12 | 526 |
| 13 | 513 |
| 14 | 555 |
| 15 | 679 |
| 16 | 624 |
| 17 | 796 |
| 18 | 752 |
| 19 | 843 |
| 20 | 827 |
| 21 | 774 |
| 22 | 647 |
| 23 | 533 |
+------+------------+
12 rows in set (0.00 sec)
My problem is that in old sets, the web service calls in the hours from [00-11] were already summed up. The simple statement as listed above would therefore lead to
mysql> SELECT hour, SUM(calls) FROM sample s GROUP BY hour;
+------+------------+
| hour | SUM(calls) |
+------+------------+
| 00 | 6243 | <------ sum of hours 00-11!
| 12 | 526 |
| 13 | 513 |
| 14 | 555 |
| 15 | 679 |
| 16 | 624 |
| 17 | 796 |
| 18 | 752 |
| 19 | 843 |
| 20 | 827 |
| 21 | 774 |
| 22 | 647 |
| 23 | 533 |
+------+------------+
13 rows in set (0.00 sec)
This is an undesirable result. To make the old sets [00,12,...,23] comparable to the new sets [00,01,...,23] I would like to have one statement that averages the value of [00] and distributes it over the missing hours, e.g.:
+------+------------+
| hour | SUM(calls) |
+------+------------+
| 00 | 6243/11 |
| 01 | 6243/11 |
[...]
| 12 | 526 |
[...]
| 23 | 533 |
+------+------------+
I can easily do this using temporary tables or views, but i don't know how to accomplish this without them.
Any ideas? Cause this is driving me crazy :P

You'll need a rowset with 12 rows in it to make a join.
The most simple solution will be combining 12 SELECT statements in a union:
SELECT COALESCE(morning.hour, sample.hour),
SUM(CASE WHEN morning.hour IS NULL THEN calls ELSE calls / 12 END) AS calls
FROM sample
LEFT JOIN
(
SELECT 0 AS hour
UNION ALL
SELECT 1
...
UNION ALL
SELECT 11
) AS morning
ON sample.hour = 0 AND sample.service IN ('old_service1', 'old_service2')
GROUP BY
1

You're probably best doing this with temp tables / views (I'd recommend a view over a temp table) or you will end up with a nasty case specific statement that will be a nightmare to manage over time.

Related

calculate unit in stock of a product

This is the question:
To find
units in stock of a product, use the InventoryTransactions table, find total quantity
purchased and subtract quantities sold and on hold.
The Inventory Transaction table:
This are the transaction type for each transaction id:
transaction id 1 = purchased, trasaction id 2 = sold, transaction id 3 = on hold
+----+-----------+
| ID | TypeName |
+----+-----------+
| 1 | Purchased |
| 2 | Sold |
| 3 | On Hold |
| 4 | Waste |
+----+-----------+
4 rows in set (0.00 sec)
The product id, quantity, and type of transaction:
SELECT productid, quantity, transactiontype FROM Inventory_Transactions ORDER BY productid;
+-----------+----------+-----------------+
| productid | quantity | transactiontype |
+-----------+----------+-----------------+
| 1 | 40 | 1 |
| 1 | 15 | 2 |
| 1 | 25 | 3 |
| 3 | 100 | 1 |
| 3 | 50 | 2 |
| 4 | 40 | 1 |
| 4 | 10 | 2 |
| 4 | 30 | 2 |
| 5 | 40 | 1 |
| 5 | 25 | 2 |
| 6 | 100 | 1 |
| 6 | 10 | 2 |
| 6 | 90 | 2 |
| 7 | 40 | 1 |
| 7 | 10 | 2 |
| 7 | 30 | 2 |
| 8 | 40 | 1 |
| 8 | 17 | 2 |
| 8 | 25 | 1 |
| 8 | 25 | 2 |
| 8 | 20 | 2 |
| 8 | 3 | 2 |
| 14 | 40 | 1 |
| 17 | 40 | 1 |
| 17 | 40 | 2 |
| 19 | 20 | 1 |
| 19 | 20 | 2 |
| 19 | 30 | 1 |
| 19 | 30 | 2 |
| 19 | 25 | 1 |
| 19 | 10 | 2 |
| 19 | 10 | 1 |
| 19 | 25 | 2 |
| 20 | 40 | 1 |
| 20 | 40 | 2 |
| 21 | 20 | 1 |
| 21 | 20 | 2 |
| 34 | 60 | 1 |
| 34 | 100 | 1 |
| 34 | 100 | 2 |
| 34 | 12 | 3 |
| 34 | 10 | 3 |
| 34 | 1 | 3 |
| 34 | 50 | 1 |
| 34 | 300 | 1 |
| 34 | 300 | 2 |
| 34 | 87 | 2 |
| 40 | 120 | 1 |
| 40 | 50 | 2 |
| 40 | 30 | 2 |
| 40 | 40 | 2 |
| 41 | 40 | 1 |
| 41 | 200 | 1 |
| 41 | 200 | 2 |
| 41 | 30 | 2 |
| 41 | 50 | 1 |
| 41 | 50 | 2 |
| 41 | 10 | 2 |
| 43 | 100 | 1 |
| 43 | 20 | 2 |
| 43 | 300 | 1 |
| 43 | 300 | 2 |
| 43 | 25 | 3 |
| 43 | 250 | 1 |
| 43 | 300 | 3 |
| 43 | 5 | 2 |
| 48 | 100 | 1 |
| 48 | 10 | 2 |
| 48 | 100 | 1 |
| 48 | 100 | 2 |
| 48 | 10 | 2 |
| 48 | 40 | 2 |
| 48 | 40 | 2 |
| 51 | 40 | 1 |
| 51 | 10 | 2 |
| 51 | 30 | 2 |
| 52 | 100 | 1 |
| 52 | 40 | 2 |
| 56 | 120 | 1 |
| 56 | 110 | 3 |
| 57 | 80 | 1 |
| 57 | 100 | 1 |
| 57 | 100 | 2 |
| 65 | 40 | 1 |
| 66 | 80 | 1 |
| 72 | 40 | 1 |
| 72 | 50 | 1 |
| 72 | 50 | 2 |
| 72 | 40 | 2 |
| 74 | 20 | 1 |
| 74 | 20 | 2 |
| 77 | 60 | 1 |
| 80 | 75 | 1 |
| 80 | 30 | 2 |
| 80 | 10 | 2 |
| 80 | 20 | 3 |
| 80 | 15 | 2 |
| 81 | 125 | 1 |
| 81 | 200 | 1 |
| 81 | 200 | 2 |
| 81 | 50 | 3 |
| 81 | 25 | 3 |
+-----------+----------+-----------------+
102 rows in set (0.00 sec)
I will need to calculate unit of stock for each productid by SUM(quantity purchased) - SUM(quantity sold) - SUM(quantity on hold)
My take:
CREATE VIEW purchased AS
SELECT productid, SUM(quantity) quantity
FROM Inventory_Transactions
WHERE transactiontype = 1
GROUP BY productid
ORDER BY productid;
CREATE VIEW sold AS
SELECT productid, SUM(quantity) quantity
FROM Inventory_Transactions
WHERE transactiontype = 2
GROUP BY productid
ORDER BY productid;
CREATE VIEW onhold AS
SELECT productid, SUM(quantity) quantity
FROM Inventory_Transactions
WHERE transactiontype = 3
GROUP BY productid
ORDER BY productid;
SELECT pur.productid, pur.quantity - so.quantity - on.quantity
FROM purchased pur, sold so, onhold on
WHERE pur.productid = so.productid = on.productid;
But I got this error
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'on WHERE pur.productid = so.productid = on.productid' at line 1
These are the individual VIEW I created above:
SELECT * FROM purchased;
+-----------+----------+
| productid | quantity |
+-----------+----------+
| 1 | 40 |
| 3 | 100 |
| 4 | 40 |
| 5 | 40 |
| 6 | 100 |
| 7 | 40 |
| 8 | 65 |
| 14 | 40 |
| 17 | 40 |
| 19 | 85 |
| 20 | 40 |
| 21 | 20 |
| 34 | 510 |
| 40 | 120 |
| 41 | 290 |
| 43 | 650 |
| 48 | 200 |
| 51 | 40 |
| 52 | 100 |
| 56 | 120 |
| 57 | 180 |
| 65 | 40 |
| 66 | 80 |
| 72 | 90 |
| 74 | 20 |
| 77 | 60 |
| 80 | 75 |
| 81 | 325 |
+-----------+----------+
28 rows in set (0.00 sec)
SELECT * FROM sold;
+-----------+----------+
| productid | quantity |
+-----------+----------+
| 1 | 15 |
| 3 | 50 |
| 4 | 40 |
| 5 | 25 |
| 6 | 100 |
| 7 | 40 |
| 8 | 65 |
| 17 | 40 |
| 19 | 85 |
| 20 | 40 |
| 21 | 20 |
| 34 | 487 |
| 40 | 120 |
| 41 | 290 |
| 43 | 325 |
| 48 | 200 |
| 51 | 40 |
| 52 | 40 |
| 57 | 100 |
| 72 | 90 |
| 74 | 20 |
| 80 | 55 |
| 81 | 200 |
+-----------+----------+
23 rows in set (0.01 sec)
SELECT * FROM onhold;
+-----------+----------+
| productid | quantity |
+-----------+----------+
| 1 | 25 |
| 34 | 23 |
| 43 | 325 |
| 56 | 110 |
| 80 | 20 |
| 81 | 75 |
+-----------+----------+
6 rows in set (0.00 sec)
I am using the northwind database
Here are all the table relationship in northwind database.
May I know how do I solve this?
The approach I would take is using something called "Conditional aggregation"
use a summed case expression to determine if it's a purchase
use a summed 2nd case expression to determine if it's a sale/hold
subtract the two
group by product
.
SELECT ProductID,
SUM(case when TransactionType = 1 then quantity else 0 end) -
SUM(case when TransactionType in (2,3) then quantity else 0 end) as AvailableInventory
FROM Inventory_Transactions
GROUP BY ProductID
As to the nature of your error:
you have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'on WHERE pur.productid = so.productid = on.productid' at line 1
on is a reserved word use onh or onhold or something for the alias
using , joins is and old technique use Inner, outer, full outer, cross join and use the on notation to specify how he tables relate
equality checks within where clauses must return true false. To date they are not trinary. If A=B but <> C what would you expect to happen? so break out your productID's so they handle all the needed joins.
you're going to have problems of matching records because not all 3 may have a value so if you match on productID for sold or hold, you may not have a product and it would fall out of your results... thus outer joins are needed if you continue with your current approach.
.
ORIGINAL
SELECT pur.productid, pur.quantity - so.quantity - on.quantity
FROM purchased pur, sold so, onhold on
WHERE pur.productid = so.productid = on.productid;
should be:
SELECT coalesce(pur.productid, so.productid,onhold.ProductID) as productid,
coalesce(pur.quantity,0) - coalesce(so.quantity,0) -
coalesce(onhold.quantity) as AvailableInventory
FROM purchased pur
FULL OUTER JOIN sold so
on pur.productid = so.productid
FULL OUTER JOIN onhold
on pur.productid = onhold.productid
OR so.productid = onhold.productid
GROUP BY coalesce(pur.productid, so.productid,onhold.ProductID);
Breaking this down
the coalesce of productID is because we don't know in which of the 1,2,3 a productID will exist. But, we need the product id to show up for any of the 3 not just purchases.
the coalesce on quantity is because if we try to subtract a NULL value, we get a NULL so we need to ensure a numeric value exists. pretend for a second product ID 1 exists in purchases but has had no sales or holds. 10 purchases - NULL = NULL... not what we want. now if the productID 2 is in sales but not purchases we'd have NULL-10-NULL... again not what we want. Also if we just used the productid from purchases it would be NULL on this record...; also not good.
we replaced the , notation which is a cross join to a full outer so we don't lose records. Now cross join would work but it takes # of purchases * #of sales * number of on hold then limits the records based on your where clause this is WAY more work than the database needs to do and on a large dataset would be VERY slow.
Discussed earlier, where clause can't be trinary it must be a binary result comparing just 2 values.
Now full outer vs left vs inner vs right....
FULL OUTER: include all records from both tables and line them up where they match on Key (productID in our example)
LEFT JOIN include all records from the first table and any that match from the 2nd
INNER Include only records which exist in both tables.
RIGHT include all records from the 2nd table and any that match from the 1st.
CROSS JOIN: all records related to all records (Very slow but there are uses; just not here)
and more...
If we can't assume each of your products has a value in each group: pur, sold, onhold; we need to use full outer joins as above; so we don't exclude any records. However even this can be an issue because we have to ensure each productID ties back to a related product in another table if it exists.
To do this we have to use an OR on the last match (kinda ugly) and as we don't know the source of productID... we have to find one using coalesce.
If we can assume all products must first exist as a purchase, we can left join the other two. A bit cleaner, but we still have to handle the situation where there may be no data in sold or on hold, so we have to coalesce the 0 in for the quantities. we don't have to coalesce the productid since we know a purchase has to exist.
SELECT pur.productid, sum(coalesce(pur.quantity,0) - coalesce(so.quantity,0) -
coalesce(onhold.quantity)) as AvailableInventory
FROM purchased pur
LEFT OUTER JOIN sold so
on pur.productid = so.productid
LEFT OUTER JOIN onhold
on pur.productid = onhold.productid
--Note: we tie back to pur both times as we know it exists there.
GROUP BY pur.productid;
Hopefully you can see the conditional aggregation is the better approach as it simplifies and reduces joins and avoids much of the coalesing we do.

Why does using with rollup give me different results when inside pivot are using sum and pivot and left join?

I have 3 tables Here the location http://rextester.com/PED43367
I failed in with roll up, can some one giving me the way?
the output i want is :
enter image description here
The result is ok, but I can't make rollup with that
Thanks for your Help
You should read up on mysql order of execution (MySQL query / clause execution order) and https://dev.mysql.com/doc/refman/5.7/en/group-by-handling.html paying particular attention to "If ONLY_FULL_GROUP_BY is disabled, a MySQL extension to the standard SQL use of GROUP BY permits the select list, HAVING condition, or ORDER BY list to refer to nonaggregated columns even if the columns are not functionally dependent on GROUP BY columns. This causes MySQL to accept the preceding query. In this case, the server is free to choose any value from each group, so unless they are the same, the values chosen are indeterminate, which is probably not what you want."
In brief then your from and joins are executed first, the group by is dodgy and the rollup adds issues.
I would separate out the group by for pivot and then add the joins using group by "properly"
select m.codes,m.version,sum(m.headcount) headount,sum(m.reghrs) reghrs, sum(m.hrsbdgt) hrsbudget,
sum(w.workhrs) workhours, sum(w.reghrs) wreghrs,
sum(d1) '02-04-2017',
sum(d2) '09-04-2017',
sum(d3) '16-04-2017',
sum(d4) '23-04-2017',
sum(d5) '30-04-2017',
sum(p.hours) as Total,
SUM(p.hours) - sum(m.HrsBdgt) RsltBdgt
from mtarget m
left join
(
select CODEPivot,categoryPivot ,
SUM(IF(pivot.selesai = '2017-04-02',pivot.hours,0)) d1,
SUM(IF(pivot.selesai = '2017-04-09',pivot.hours,0)) d2,
SUM(IF(pivot.selesai = '2017-04-16',pivot.hours,0)) d3,
SUM(IF(pivot.selesai = '2017-04-23',pivot.hours,0)) d4,
SUM(IF(pivot.selesai = '2017-04-30',pivot.hours,0)) d5,
sum(pivot.hours) hours
from pivot
group by CODEPivot,categoryPivot
) p on
m.codeS = p.CODEPivot
and m.version = p.categoryPivot
left join whweek w on
w.Code = p.CODEPivot
and w.version = p.CategoryPivot
group by codes,version with rollup
+-------+---------+----------+--------+-----------+-----------+---------+------------+------------+------------+------------+------------+-------+----------+
| codes | version | headount | reghrs | hrsbudget | workhours | wreghrs | 02-04-2017 | 09-04-2017 | 16-04-2017 | 23-04-2017 | 30-04-2017 | Total | RsltBdgt |
+-------+---------+----------+--------+-----------+-----------+---------+------------+------------+------------+------------+------------+-------+----------+
| FII | YAA | 3 | 432 | 35 | 144 | 432 | 28 | 28 | 14 | 24 | 41 | 135 | 100 |
| FII | NULL | 3 | 432 | 35 | 144 | 432 | 28 | 28 | 14 | 24 | 41 | 135 | 100 |
| IDS | YAA | 3 | 432 | 35 | 144 | 432 | 8 | 0 | 0 | 0 | 0 | 8 | -27 |
| IDS | NULL | 3 | 432 | 35 | 144 | 432 | 8 | 0 | 0 | 0 | 0 | 8 | -27 |
| RRT | BKK | 1 | 144 | 12 | 144 | 144 | 8 | 3 | 16 | 15 | 32 | 74 | 62 |
| RRT | WESEL | 1 | 144 | 12 | 144 | 144 | 0 | 14 | 7 | 2 | 0 | 23 | 11 |
| RRT | YAA | 9 | 1296 | 104 | 144 | 1296 | 67 | 98 | 135 | 103 | 119 | 522 | 418 |
| RRT | NULL | 11 | 1584 | 128 | 432 | 1584 | 75 | 115 | 158 | 120 | 151 | 619 | 491 |
| NULL | NULL | 17 | 2448 | 198 | 720 | 2448 | 111 | 143 | 172 | 144 | 192 | 762 | 564 |
+-------+---------+----------+--------+-----------+-----------+---------+------------+------------+------------+------------+------------+-------+----------+
9 rows in set (0.00 sec)

MYSQL SELECT most recent of id and ORDER BY

What I am trying to do is get the most recent result for each resort_id and then ORDER BY snow_depth. The first two parts I have managed. The ordering is the part that doesn't work.
What I have so far
SELECT * FROM snow_conditions t1
NATURAL JOIN ( SELECT MAX(weather_id) AS weather_id, resort_id FROM snow_conditions
GROUP BY resort_id ) t2
ORDER BY snow_depth DESC
weather_id is auto incremented, so I use it instead of save_time to reduce calculation resource.
The thing that is confusing me is the result comes out in some weird partial order of snow_depth.
+-----------+------------+------------+
| resort_id | weather_id | snow_depth |
+-----------+------------+------------+
| 888 | 827 | 90 |
| 943 | 835 | 90 |
| 860 | 839 | 75 |
| 17 | 828 | 71 |
| 26 | 826 | 70 |
| 9 | 852 | 60 |
| 16 | 831 | 292 |
| 296 | 862 | 170 |
| 20 | 843 | 168 |
| 5 | 842 | 165 |
| 36 | 838 | 160 |
| 17 | 17 | 0 |
| 26 | 26 | 0 |
+-----------+------------+------------+
When really it should appear like this
+-----------+------------+------------+
| resort_id | weather_id | snow_depth |
+-----------+------------+------------+
| 16 | 831 | 292 |
| 296 | 862 | 170 |
| 20 | 843 | 168 |
| 5 | 842 | 165 |
| 36 | 838 | 160 |
| 888 | 827 | 90 |
| 943 | 835 | 90 |
| 860 | 839 | 75 |
| 17 | 828 | 71 |
| 26 | 826 | 70 |
| 9 | 852 | 60 |
| 17 | 17 | 0 |
| 26 | 26 | 0 |
+-----------+------------+------------+
I have tried just about every relevant looking MySQL query I could find on here but they all encounter the same issue or don't work.
EDIT: I should mention this table contains thousands of rows, with hundreds of rows for each resort_id. It's done this way so I can use it to generate a snowfall history.
I think you should check your database for data type of snow_depth it should not be varchar. Your result sounds like it is varchar so if it is then change it to int or any numeric type
your result already sorted by snow_depth but the snow_depth column is varchar data type. change it or you can use this:
cast(snow_depth as unsigned) DESC
so, your all query should be:
SELECT * FROM snow_conditions t1
NATURAL JOIN ( SELECT MAX(weather_id) AS weather_id, resort_id FROM snow_conditions
GROUP BY resort_id ) t2
ORDER BY cast(snow_depth as unsigned) DESC

Mysql difference between max() and min()?

I got a problem with a mySql query and max() function.
If I do :
Select * from Data group by experiment having min(timestamp)
This query return what I want, and correct value.
I got this :
+----------+---------+----------+---------------------+----------------+------------+
| id | mote_id | label_id | timestamp | value | experiment |
+----------+---------+----------+---------------------+----------------+------------+
| 3768806 | 10 | 30 | 2014-04-22 14:37:07 | 0 | 13 |
| 10989209 | 12 | 22 | 2014-04-25 10:44:03 | 2.532958984375 | 15 |
| 11943537 | 6 | 19 | 2014-05-05 17:20:15 | 1228 | 16 |
| 12042549 | 16 | 26 | 2014-05-06 10:48:59 | 22.86 | 17 |
| 12176642 | 15 | 23 | 2014-05-07 15:19:35 | 0 | 18 |
| 12195344 | 10 | 6 | 2014-05-07 15:27:23 | 3460 | 19 |
| 12222470 | 15 | 8 | 2014-05-07 15:38:38 | 1 | 21 |
| 12343934 | 10 | 19 | 2014-05-12 10:35:42 | 742 | 23 |
+----------+---------+----------+---------------------+----------------+------------+
But, if i do :
Select * from Data group by experiment having max(timestamp)
This query return wrong values... like this :
+----------+---------+----------+---------------------+----------------+------------+
| id | mote_id | label_id | timestamp | value | experiment |
+----------+---------+----------+---------------------+----------------+------------+
| 3768806 | 10 | 30 | 2014-04-22 14:37:07 | 0 | 13 |
| 10989209 | 12 | 22 | 2014-04-25 10:44:03 | 2.532958984375 | 15 |
| 11943537 | 6 | 19 | 2014-05-05 17:20:15 | 1228 | 16 |
| 12042549 | 16 | 26 | 2014-05-06 10:48:59 | 22.86 | 17 |
| 12176642 | 15 | 23 | 2014-05-07 15:19:35 | 0 | 18 |
| 12195344 | 10 | 6 | 2014-05-07 15:27:23 | 3460 | 19 |
| 12222470 | 15 | 8 | 2014-05-07 15:38:38 | 1 | 21 |
| 12343934 | 10 | 19 | 2014-05-12 10:35:42 | 742 | 23 |
+----------+---------+----------+---------------------+----------------+------------+
In the first query, if I replace min(timestamp) by timestamp=min(timestamp), it works, but in the second, "timestamp=max(timestamp)" return nothing
Finally, Select experiment,max(timestamp) return correct values.
mysql> select *,max(timestamp) from Data group by experiment;
+----------+---------+----------+---------------------+----------------+------------+---------------------+
| id | mote_id | label_id | timestamp | value | experiment | max(timestamp) |
+----------+---------+----------+---------------------+----------------+------------+---------------------+
| 3768806 | 10 | 30 | 2014-04-22 14:37:07 | 0 | 13 | 2014-04-24 16:03:29 |
| 10989209 | 12 | 22 | 2014-04-25 10:44:03 | 2.532958984375 | 15 | 2014-05-05 10:34:35 |
| 11943537 | 6 | 19 | 2014-05-05 17:20:15 | 1228 | 16 | 2014-05-06 10:35:15 |
| 12042549 | 16 | 26 | 2014-05-06 10:48:59 | 22.86 | 17 | 2014-05-07 15:19:33 |
| 12176642 | 15 | 23 | 2014-05-07 15:19:35 | 0 | 18 | 2014-05-07 15:27:23 |
| 12195344 | 10 | 6 | 2014-05-07 15:27:23 | 3460 | 19 | 2014-05-07 15:38:01 |
| 12222470 | 15 | 8 | 2014-05-07 15:38:38 | 1 | 21 | 2014-05-07 16:30:38 |
| 12343934 | 10 | 19 | 2014-05-12 10:35:42 | 742 | 23 | 2014-05-14 09:25:44 |
+----------+---------+----------+---------------------+----------------+------------+---------------------+
I know I can make a subquery to solve my probleme, but the tables contains thousands rows, and this solution is too long...
Ps : I can't use Select*, max(timestamp) even if it works because the query is run by EJB in JEE.
You select not determined values grouped by field experiment. No one can give you a guarantee that non-agregated fields would correspond to MIN or MAX values of some aggregated field.
You HAVE TO use sub-query or self-join to get the right records.
See more here: http://dev.mysql.com/doc/refman/5.6/en/example-maximum-column-group-row.html
The HAVING clause expects a boolean expression. In other DBMS your code sample would trigger an error. In MySQL, you'll get the expression cast to boolean:
Zero → false
Non-zero → true
And since your expression is constant for the whole set, it won't filter out partial rows.
As about this:
HAVING timestamp = max(timestamp)
The HAVING clause evaluates after WHERE and GROUP BY. At that point, using individual row values of the timestamp column doesn't make any sense. As usual, MySQL allows that but you must take into account that:
In standard SQL, a query that includes a GROUP BY clause cannot refer
to nonaggregated columns in the HAVING clause that are not named in
the GROUP BY clause. A MySQL extension permits references to such
columns to simplify calculations. This extension assumes that the
nongrouped columns will have the same group-wise values. Otherwise,
the result is indeterminate.
In other words, your results are arbitrary (not even random).

mysql: If a value appears more than once, get values from the others similar rows and create new columns

Here is an example of my table patients:
id | case_id | patient_id | syndrome | age |
------------------------------------------------------
1 | 23 | 24 | stable | 45 |
2 | 24 | 25 | stable | 64 |
3 | 25 | 24 | coronary | 46 |
4 | 26 | 27 | stable | 73 |
5 | 27 | 24 | stable | 48 |
6 | 28 | 25 | coronary | 67 |
7 | 29 | 40 | coronary | 68 |
If patient_id appears more than once, i only want to show the first row and add extra columns to this row containing the values of the others similar patient_ids.
For example
id | case_id | patient_id | syndrome | age | syndrome2 | age2 | syndrome3 | age3
--------------------------------------------------------------------------------------------
1 | 23 | 24 | stable | 45 | coronary | 46 | stable | 48
2 | 24 | 25 | stable | 64 | coronary | 67 | |
7 | 29 | 40 | coronary | 68 |
Is this feasible using mysql code?
Currently, I have this code:
SELECT *, count(patients.patient_id) as PatientsNo FROM patients
GROUP BY patient_id
HAVING COUNT(patient_id) > 1
Any suggestions please?
Thank you in advance,
Zinon