So, I have an array id=>time and a table.
| id | text | created_at |
How to get all rows where CREATED_AT>array['id'] and ID=id in one query?
i can do, something like this
foreach (array as $key=>$value) {
query("SELECT * FROM table WHERE CREATED_AT>$value and ID=$key");
}
but i would like to put it all in one query.
Sample data:
| id | text | created_at |
--------------------------
| 1 | aaaa | 123 |
| 2 | bbbb | 124 |
| 1 | cccc | 122 |
| 3 | dddd | 125 |
| 1 | eeee | 125 |
array( '1' => 123, '2' => 125, '3' => 124);
Query should return this rows:
| 1 | aaaa | 123 |
| 3 | dddd | 125 |
| 1 | eeee | 125 |
You could do a long series of
$my_query = "SELECT * FROM table WHERE";
$counter = 0;
foreach (array as $key=>$value) {
if ($counter > 0)
$my_query += " OR ";
$my_query += "(CREATED_AT>$value and ID=$key)";
$counter++;
}
However this is ugly. I wouldn't recommend doing it. Aside from that I think there's no easy way to do this in one query. It would be easy if there was just a single batch of IDs you are querying for, but given both criteria I can't think of any other way.
I don't think it's such a bad idea to do it in a for loop... It's definitely more readable than the code I gave above.
Related
Yii2 provides ActiveRecord::findBySql für raw SQL queries:
public static yii\db\ActiveQuery findBySql ( $sql, $params = [] )
Since there is no hint in the documentation: How to specify $params?
UPDATE
The reason there isn't any docs about the params passed to the findBySql() method is because the method returns the instance of ActiveQuery and if you see the last line of this method in yii\db\ActiveRecord.php it sets the $params via $query->params($params), means the yii\db\ActiveQuery function params($params) which defines the $params as
$params list of query parameter values indexed by parameter
placeholders. For example, [':name' => 'Dan', ':age' => 31].
I guess you should try the following way if lets say you have a table with name product
+----+-----------------+------------+--------+
| id | name | is_deleted | price |
+----+-----------------+------------+--------+
| 1 | shugal | 1 | 65.00 |
| 2 | spoon | 1 | 55.00 |
| 4 | kettle | 1 | 15.00 |
| 5 | spoon | 0 | 15.00 |
| 6 | plates | 0 | 105.00 |
| 7 | dishes | 0 | 15.00 |
| 8 | forks | 0 | 15.00 |
| 10 | pressure cooker | 0 | 203.00 |
| 16 | shugal | 1 | 65.00 |
| 17 | something | 0 | 25.00 |
| 25 | multi product | 0 | 0.00 |
| 66 | pans | 0 | 15.00 |
+----+-----------------+------------+--------+
using the following code you can select all the products that are deleted using params
$q = Product::findBySql(
"SELECT * FROM product where is_deleted=:deleted",
[':deleted' => 1]
)->all();
Hope this helps
I need a little bit of help with making a complicated query, i will try to explain what i am trying to accomplish down below.
Here is my data
table_one
+---------+---------+----------+----------+
| user_id | poly_id | in | out |
+---------+---------+----------+----------+
| 900 | 1 | 20-12-17 | 20-12-17 |
| 900 | 2 | 21-12-17 | 22-12-17 |
| 900 | 3 | 22-12-17 | 24-12-17 |
| 900 | 1 | 23-12-17 | 26-12-17 |
| 444 | 4 | 24-12-17 | 28-12-17 |
| 444 | 4 | 25-12-17 | 30-12-17 |
| 444 | 5 | 26-12-17 | 01-01-18 |
| 444 | 3 | 27-12-17 | 03-01-18 |
| 900 | 2 | 28-12-17 | 05-01-18 |
| 900 | 1 | 29-12-17 | 07-01-18 |
| 444 | 2 | 30-12-17 | 09-01-18 |
+---------+---------+----------+----------+
table_two
+----+---------+-------------+---------+
| id | name | type | product |
+----+---------+-------------+---------+
| 1 | city 1 | gas station | general |
| 2 | city 2 | workshop | general |
| 3 | city 3 | paint | bikes |
| 4 | city 4 | paint | general |
| 5 | city 5 | gas station | cars |
| 6 | city 6 | gas station | bikes |
| 7 | city 7 | paint | cars |
| 8 | city 8 | workshop | cars |
| 9 | city 9 | gas station | general |
| 10 | city 10 | gas station | cars |
| 11 | city 11 | gas station | general |
+----+---------+-------------+---------+
i have a working solution that looks like this
//results comes from somewhere else, it looks something like this for example:
array (
"user_id" => "poly_id of the last gas station"
"900" => 1,
"444" => 10
)
foreach ($result AS $res ) {
$query = "
SELECT
table_one.name AS name
FROM
`table_one`
LEFT JOIN
`table_two` ON table_one.poly_id = table_two.id
WHERE
`table_two`.type = 'gas station '
AND
table_one.user_id = $res['user_id']
AND
table_one.poly_id != $res['poly_id']
AND
table_one.in >= "some date from'
AND
table_one.out <= 'some date to'
AND
(FIND_IN_SET('general', table_two.product) > 0 OR FIND_IN_SET('cars', table_two.product) > 0 )
ORDER BY out DESC LIMIT 1
";
//if the results is not empty use the result['name']
}
The idea is: I have the user last gas station, but i need to find the previous one between a date range.
As i said, the above example is working just fine, however i need to be able to process multiple results at once, and sometimes the results are ~2000.
Which means 2000+ queries per request.
Is it even possible to somehow optimize this loop of queries into a single one, so I don't do 2000 queries per request ?
If possible, how :D
Thanks.
This query will return result contains user_id with it's last
enter in the given periode.
one thing here because you are
using date not date time if the user exit in the same
day two time you will have two record of that user you can skip the second
record in you code
select
user_id,
in,
out
from table_one t1
INNER JOIN (
select
user_id
max(out) as 'max_out',
from
table_one
where
in >= ? AND
out <= ? AND
ploy_id not in [list_of_unwanted_ploy_id]
-- you can specify any condition here
group by user_id
) l_out on t1.user_id = l_out.user_id and t1.out = l_out.max_out
where
t1.user_id in [list_of_user_id]
I have problems formatting a json-object as a result from an Ajax-Call the way I want it. Also I don't know if my approach is the best possible way..
To explain the situation:
Let's say I have names and heights of persons and their favorite colors (which can be several) stored in my db. the tables look like this
persons:
+ id | name | height +
+++++++++++++++++++++++++++
| 1 | peter | 185 |
| 2 | paul | 176 |
colors:
+ id | color +
++++++++++++++++
| 1 | green |
| 2 | blue |
| 3 | yellow |
| 4 | red |
person_color:
+ id | id_person | id_color +
++++++++++++++++++++++++++++++
| 1 | 1 | 1 |
| 2 | 1 | 2 |
| 3 | 1 | 3 |
| 4 | 2 | 2 |
| 5 | 2 | 4 |
I get the data I need by left-joining the tables like this
SELECT id, name, height, colors.color
FROM persons
LEFT JOIN person_color
ON persons.id = person_color.id_person
LEFT JOIN colors
ON person_color.id_color = color.id
This all works fine.
Then I json_encode the query-result and hand the object back to the script.
In case of a successful call, I create a html-table by going through the returned object like this
var html = "<table>";
$.each(msg) = function(key, val) {
html += "<tr>";
$.each(val) = function(key2, val2){
html += "<td>+val2+</td>";
}
html += "</tr>";
}
html += "</table>";
That gives me this table as a result:
+ id | name | groesse | farbe +
+++++++++++++++++++++++++++++++++++++++++
| 1 | peter | 185 | green |
| 1 | peter | 185 | blue |
| 1 | peter | 185 | yellow |
| 2 | paul | 176 | blue |
| 2 | paul | 176 | red |
So far, so good. But what i want to achieve is to display the result in a form like this:
+ id + name + height + color +
+++++++++++++++++++++++++++++++++++++++++++++++++++++
| 1 | peter | 185 | green, blue, yellow |
| 2 | paul | 176 | blue, red |
Shouldn't be too difficult, but I am going in circles..
Also I am not sure whether to change the script creating the html-table, or if there is a clever way to alter the SQL-statement to produce something in the right form.
Any hint to either of this would be highly appreciated!
Thanks in advance,
Paco
There's GROUP_CONCAT aggregating function in mysql:
SELECT id, name, height, GROUP_CONCAT(colors.color SEPARATOR ', ') as color
FROM persons
LEFT JOIN person_color
ON persons.id = person_color.id_person
LEFT JOIN colors
ON person_color.id_color = color.id
GROUP BY id
i have the following table
table 1
------------------------------------------
| animal_id | animal_name | animal_type |
------------------------------------------
| 1 | kay | cat |
| 2 | sandy | dog |
------------------------------------------
table 2
--------------------------------------------------------------------------
| vaccine_id | animal_id | vaccine_name | vaccine_status | vaccine_date |
--------------------------------------------------------------------------
| 1 | 1 | rabies | done | 2015-09-09 |
| 2 | 1 | chlamydiasis | undone | 2015-09-15 |
| 3 | 1 | parasite | undone | 2015-10-20 |
| 4 | 2 | parasytosis | undone | 2015-11-10 |
| 5 | 2 | rabies | undone | 2015-11-05 |
expected result:
--------------------------------------------------------------------------------------------------------------
| animal_id | animal_name | animal_type | vacccine_id | vaccine_name | vaccine_status | vaccine_date |
--------------------------------------------------------------------------------------------------------------
| 1 | kay | cat | 2 | chlamydiasis | undone | 2015-09-15 |
| 2 | sandy | dog | 5 | rabies | undone | 2015-11-05 |
the result will show all the first row of each unique value between two tables with the most recent vaccine_date and the condition where the vaccine_status is undone. I'm using SQL by the way
For complex queries you often need to manipulate the data with something like PHP. For example, using 2 queries on the data you provided:
<?php
$link=mysqli_connect("host","user","password","database");
// Start with the list of animals
$sql = "SELECT * FROM animals";
$res = $link->query($sql);
for($i=0; $i<mysqli_num_rows($res); ++$i){
$row1 = mysqli_fetch_assoc($res);
$animal_id = $row1['animal_id'];
$sql = "SELECT * FROM vaccines WHERE animal_id = $animal_id AND vaccine_status = 'undone' ORDER BY vaccine_date ASC LIMIT 1";
$res2 = $link->query($sql);
$row2 = mysqli_fetch_assoc($res2);
$arr[$animal_id] = array();
array_push($arr[$animal_id], $row1['animal_name'], $row1['animal_type'], $row2['vaccine_id'], $row2['vaccine_name'], $row2['vaccine_status'], $row2['vaccine_date']);
}
echo "RESULT:";
echo "<table border=1><tr><th>animal_id</th><th>animal_name</th><th>animal_type</th><th>vaccine_id</th><th>vaccine_name</th><th>vaccine_status</th><th>vaccine_date</th></tr>";
foreach($arr as $key => $val){
echo "<tr><td>$key</td><td>".implode("</td><td>", $val)."</td></tr><br>";
}
?>
...produces the following output:
I have a MySQL table with a million rows. The result of my query needs to contain 100 rows and has to be ordered by date.
I would now like to add a clause to the query that makes it possible to tell the database to "start the result with the row that comes after the row with the id '5'", for example. My result would therefore include the rows with the ids 4, 3, 2, 6, 8, ...
Are you, dear reader, the sought database wizard who could put me out of my misery? ;)
Query:
SELECT id, type, content, date
FROM my_table
WHERE type = 'FI'
ORDER BY date ASC
LIMIT 100;
Result:
| id | type | content | date |
|----|------|----------|------------|
| 7 | FI | ContentR | 2014-01-01 |
| 9 | FI | ContentS | 2014-01-13 |
| 1 | FI | ContentT | 2014-02-09 |
| 5 | FI | ContentU | 2014-03-27 |
| 4 | FI | ContentV | 2014-03-30 | ---|
| 3 | FI | ContentW | 2014-04-01 | |
| 2 | FI | ContentX | 2014-06-10 | |- The result I want
| 6 | FI | ContentY | 2014-09-03 | |
| 8 | FI | ContentZ | 2014-12-09 | |
... ---|
SELECT id, type, content, date
FROM my_table
WHERE type = 'FI'
AND date > (SELECT date FROM my_table WHERE id = 5)
ORDER BY date ASC
LIMIT 100;