Mysql SELECT different - php

I have a question.
My database table is something like this:
| ID | Name | Value | param |
| 1 | Michael | 290 | X |
| 2 | John | 300 | X |
| 3 | Michael | 270 | X |
| 4 | John | 280 | X |
| 5 | Michael | 256 | Y |
| 6 | Michael | 230 | Y |
¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨
So, I want to use a form to select the latest rows with different param but equal name.
For example, if I search for "Michael", I want to use PHP to show the latest value for the param X and the latest value for the param Y (returning 2 rows).
Michael: Param Y: 230
Michael: Param X: 270
And if I search for "John" I get:
John: Param X: 280.
The code
$sql = "SELECT * FROM thetable WHERE name = 'Michael' ORDER BY ID DESC";
$result = mysql_query($sql);
Now I just want for it to select only the latest rows with different param.
Thanks in advance.

Are the approaches listed won't work with n variable "params". I think something similar may work:
SELECT
t.*
FROM Table1 t
JOIN
(SELECT
max(id) AS maxid
FROM Table1
GROUP BY name,param) x
on x.maxid = t.id
WHERE name='Michael'
See http://sqlfiddle.com/#!2/64dc4/11

Use UNION
SELECT * From table WHERE name='Michael' AND PARAM='X' ORDER BY ID DESC LIMIT 1
UNION
SELECT * From table WHERE name='Michael' AND PARAM='Y' ORDER BY ID DESC LIMIT 1

use LIMIT if you want to select just one row ( hope i understood the question )
$sql = "SELECT * FROM thetable WHERE name = 'Michael' AND param = 'x' ORDER BY Value DESC LIMIT 1
UNION
SELECT * FROM thetable WHERE name = 'Michael' AND param = 'y' ORDER BY Value DESC LIMIT 1"

Related

How do I get distinct rows by a column?

I have a huge number of rows that I'd like to get say, last 5 records inserted in that database from 10 different users. If the same user inserted the last 3 rows into database, we must get one row, skip the others two and move to get a row per user, until it count up to 5.
A database like that:
user_id | news_id | title
1 | 1 | foo-1
2 | 2 | foo-2
3 | 3 | foo-3
1 | 4 | baa
4 | 5 | baa0
5 | 6 | baa1
5 | 7 | baa2
6 | 8 | baa3
7 | 9 | baa4
Should return:
user_id | news_id | title
1 | 1 | foo-1
2 | 2 | foo-2
3 | 3 | foo-3
4 | 5 | baa0
5 | 6 | baa1
The current filter was done by PHP, like this:
$used = array();
while ($data = mysql_fetch_array($query)) {
$uid = $data['user_id'];
if(in_array($uid, $used))
continue;
array_push($used, $uid);
// do something with data
}
But I want to refactor it, and do the filter purely by mysql, if possible. I don't know much MySql and that's why I'm having problem to archive this...
Here's what I've tried
select DISTINCT(user_id), news_id, title from XXX
WHERE GROUP BY (news_id) DESC
LIMIT 0,5
How can I do that?
1 way you can do it is to generate a partitioned row number per user and then select 5 records where RowNumber = 1.
SELECT *
FROM
(
SELECT
d.user_id
,d.news_id
,d.title
,(#rn:= if(#uid = user_id, #rn + 1,
if(#uid:=user_id,1,1)
)
) as RowNumber
FROM
Data d
CROSS JOIN (SELECT #uid:=-1, #rn:=0) vars
ORDER BY
user_id
,news_id
) t
WHERE
t.RowNumber = 1
ORDER BY news_id
LIMIT 5;
http://rextester.com/JRIZI7402 - example to show it working
Note you can change the row order by simply changing the ORDER BY statement of the derived table so if you have a column that will signify the latest record e.g. an identity column or a datetime column you can use that, but user_id must be the first criteria to be partitioned correctly.
Do it from your query.
"SELECT * FROM table GROUP BY user_id ORDER BY news_id DESC LIMIT 5"
well, i think this will achieve what you are after.
select user_id, news_id, title from tableName
GROUP BY user_id
ORDER BY news_id DESC
LIMIT 0,5
Hope this helps!

How to write MySql select statement to get all defined settings or default settings not overridden for an id in one statement

In a table myTable defined as:
+----+---------+-----------+
| id | name | value |
|----+---------+-----------+
| 7 | hand | right |
| 5 | hand | left |
| 0 | hand | both |
| 0 | feet | both |
| 0 | eyes | green |
| 9 | eyes | blue |
| 2 | eyes | white |
| 2 | hand | raised |
+----+---------+-----------+
Default settings are controlled by id = 0.
My question is how to write a select statement to get name,value for id = 5 in one query that will include set for id = 5 and any defaults not overridden.
The results should be:
+---------+-----------+
| name | value |
+---------+-----------+
| hand | left |
| feet | both |
| eyes | green |
+---------+-----------+
It isn't clarified if the ordering of the result set is important, so might as well try:
SELECT name,
value
FROM MyTable
WHERE id = 5
AND id NOT IN
(
SELECT id
FROM MyTable
WHERE id = 0
GROUP BY MyTable.id
)
UNION
SELECT name,
value
FROM MyTable
WHERE id = 0
AND name NOT IN
(
SELECT name
FROM MyTable
WHERE id = 5
GROUP BY MyTable.name
)
Disclaimer: Tested in SQL Server, but not using anything specific to that version of SQL.
seems this one may work for you:
SELECT id,name,value
FROM test
WHERE id = 5
UNION
SELECT id,name,value
FROM test
WHERE id=0
and name not in (select name from test where id=5)
The following does not return three rows in the result set, it only returns a single row with columns hand, feet and eyes, so it may not work for you. But it should return the data that you're looking for given your conditions:
SELECT (CASE
WHEN EXISTS(SELECT 1 FROM myTable WHERE name='hand' AND id=5)
THEN (SELECT `value` FROM myTable WHERE name='hand' AND id=5)
ELSE (SELECT `value` FROM myTable WHERE name='hand' AND id=0)
END) AS hand,
(CASE
WHEN EXISTS(SELECT 1 FROM myTable WHERE name='feet' AND id=5)
THEN (SELECT `value` FROM myTable WHERE name='feet' AND id=5)
ELSE (SELECT `value` FROM myTable WHERE name='feet' AND id=0)
END) AS feet,
(CASE
WHEN EXISTS(SELECT 1 FROM myTable WHERE name='eyes' AND id=5)
THEN (SELECT `value` FROM myTable WHERE name='eyes' AND id=5)
ELSE (SELECT `value` FROM myTable WHERE name='eyes' AND id=0)
END) AS eyes
;
Output:
+---------+-----------+-----------+
| hand | feet | eyes |
+---------+-----------+-----------+
| left | both | green |
+---------+-----------+-----------+
This is approach generates 10 different SELECT statements rather than 1, and the accepted answer is, for most applications, probably a better way to go about it.
SELECT * FROM mytable WHERE ID = 5
UNION
SELECT * FROM mytable WHERE ID = 0 AND name NOT IN (SELECT name FROM MyTable
WHERE id = 5)
Should get you the right answer.
http://sqlfiddle.com/#!9/1f516/14

Two mysql selects in one query - one after another

I have a mysql table like this:
+----+------+
| id | rank |
+----+------+
| 1 | 2 |
+----+------+
| 2 | -1 |
+----+------+
| 3 | 5 |
+----+------+
| 4 | 1 |
+----+------+
| 5 | -1 |
+----+------+
| 6 | -1 |
+----+------+
| 7 | 8 |
+----+------+
| 8 | -1 |
+----+------+
Now I want to get the ids in the following order: At first
WHERE rank >= 1 ORDER BY rank ASC
and afterwards:
WHERE rank = -1
How can I get this in only one mysql_query()?
Try something like:
SELECT *
FROM mytable
WHERE rank >= 1
ORDER BY rank
UNION
SELECT *
FROM mytable
WHERE rank = -1
OR something like:
SELECT *
FROM mytable
WHERE rank >= 1
ORDER BY CASE WHEN rank>=1
THEN 0
ELSE 1,rank
Proposed answer:
SELECT id FROM myTable WHERE rank >= 1 ORDER BY rank ASC
UNION
SELECT id FROM myTable WHERE rank = -1
From my understanding, you wanted a column of id's, starting with the ids WHERE rank >= 1 ORDER BY rank ASC and ending with the ids WHERE rank = -1.
The previous sql query uses UNION which joins two resulting tables from separate SELECT queries. UNION can only be applied when you have the same mount of generated columns from each SELECT query, so that's a good thought to keep in mind if later you want to increase the amount of columns obtained.
You can also map rank with ELT.
sample
SELECT *
FROM mytable
ORDER BY ELT(rank+2,99,0,1,2,3,4,5,6,7,8) ASC;

Double SQL Query - JOIN

I need a double SELECT sql query from 2 different tables with names visits & items
1.: SELECT visitid, visitdate, visitreason FROM visits WHERE personid = 10
2.: SELECT itemid, itemname, itemtime FROM items WHERE itemvisitid= visitid
I think I need to do a JOIN but don’t know exactly how.
Table examples:
Table: visits
visitid | personid | visitdate | visitreason
1 | 10 | 05/07/2014 | no reason
2 | 10 | 06/07/2014 | some reason
3 | 12 | 06/07/2014 | no reason
4 | 10 | 12/07/2014 | some other reason
Table: items
itemid | personid | itemvisitid | itemname | itemtime
1 | 10 | 2 | box | 23
2 | 10 | 2 | clock | 70
3 | 10 | null | water | 50
4 | 10 | null | paper | 40
5 | 12 | 3 | box | 26
What I have now is this:
$query = "SELECT visitid, visitdate, visitreason FROM visits WHERE personid = '10' ORDER BY visitdate DESC";
// 2nd select: "SELECT itemid, itemname, itemtime FROM items WHERE itemvisitid= visitid";
$db->setQuery($query);
$results = $db->query();
while($row = mysqli_fetch_array($results)){
echo "<tr>
<td>".$row['visitid'].", ".$row['visitdate']."</td>
<td>".$row['visitreason']."</td>
<td>".$row['itemid'].",".$row['itemname'].", ".$row['itemtime']."</td>
</tr>";
}
I need results to be something like this:
<tr>
<td>1, 05/07/2014</td><td>no reason</td><td></td>
<td>2, 06/07/2014</td><td>some reason</td><td>1, box, 23<br />2, clock, 70</td>
<td>4, 12/07/2014</td><td>some other reason</td><td></td>
</tr>
I guess your might to use GROUP_CONCAT like this:
DEMO: http://sqlfiddle.com/#!2/9d4e22/15
SELECT visitid, DATE_FORMAT(visitdate,'%m/%d/%Y'), visitreason,
GROUP_CONCAT(itemid,itemname, itemtime)
FROM visits left join items on visits.visitid = items.itemvisitid
WHERE visits.personid = 10
GROUP BY visitid, visitdate, visitreason
You might want to read this to know GROUP_CONCAT :
How to use GROUP_CONCAT in a CONCAT in MySQL
The document of GROUP_CONCAT() is here:
http://dev.mysql.com/doc/refman/5.0/en/group-by-functions.html#function_group-concat
hope this helps.
SELECT `visits`.`visitid`, `visits`.`visitdate`, `visits`.`visitreason`,`items`.`itemname`, `items`.`itemtime` from `visits` INNER JOIN `items` ON `visits`.`personid`=`items`.`personid` WHERE `visits`.`personid` = '10' ORDER BY `visits`.`visitdate` DESC
if there is any error please change the field name personid in 'items' table.and then check.
This query:
SELECT v.visitid,
v.visitdate,
v.visitreason,
i.itemid,
i.itemname,
i.itemtime
FROM visits v
INNER JOIN items i
ON ( v.visitid = i.itemvisitid )
WHERE v.person_id = 10
ORDER BY v.visitdate DESC,
i.itemid ASC
will link both tables and produce a resultset that you can traverse using a double loop. The outer loop to process changes to the visit, and the inner to add every item visited in a particular visit.

SQL query to select only the maximum items?

I have this table: I want to search by UID
ID | VID | UID
1 | 1 | 5
1 | 1 | 6
1 | 2 | 6
2 | 3 | 5
2 | 3 | 6
2 | 4 | 6
I want to end up with this result:
ID | VID | UID
1 | 2 | 6
2 | 4 | 6
In other words, only select the entries where the VID is MAX of the UID but keeping in min NID could differ. Something like this I suppose:
select * from TABLE where uid = 6 and max(vid)
???
But this doesn't work?
One way is to order by the value in descending order (so the max is at the top), then just select the first result.
SELECT t.ID,
t.VID,
t.UID
FROM table t
WHERE t.ID = 1
ORDER BY t.VID DESC
LIMIT 1
Or do you mean you want all rows where t.VID is the highest value? In which case you could do something like this,
SELECT t.ID,
t.VID,
t.UID
FROM table t
WHERE t.ID = 1
AND t.VID = (SELECT MAX(VID) FROM table);
EDIT: Based on the edit to your question, it looks like you just want the max VID value for each ID? If I'm understanding you correctly, then this should give you what you need.
SELECT t.ID,
max(t.VID) as VID,
t.UID
FROM table t
WHERE t.UID = 6
GROUP BY t.ID
You need to have a subquery. This should work:
select * from TABLE where ID='1' AND VID=(select max(VID) from TABLE)
I expect your real-life example is more complicated (at least has more data).
This query will give you the row you want.
SELECT id,vid, uid
FROM TABLE
where id = 1
and vid in (select max(vid) from TABLE where id = 1)

Categories