Retrieve mysql data without any order applied - mysql

I have a table with the name of actions with primary key of action_id, i am retrieving data from this table as passing my own ordered action_ids for example
$actionIds = array(5,9,10,21,3,18,4);
$actionsTb = Engine_Api::_()->getDbtable('actions','activity');
$postSelect = $actionsTb->select()
->where('action_id IN(?)', $actionIds)
->where('type = ?', 'status')
;
now the issue is when i get the result back its in ascending order, like ( 3,4,5,9,10,18,21 ) but what i want the order of result as i passed the action ids means don't want to apply any order on the result.
please help me. you can reply with simple query too.

Since your using php, why not use loop to dynamically create where clause here is the code
$where = "action_id IN(";
for($x=0; $x<count($actionIds); $x++)
{
// code for adding comma in every end of id
if($x==count($actionIds)-1)
{
// found the last data in array add closing parenthesis in IN funtion
$where.=$actionIds[$x].")";
}
else
{
$where.=$actionIds[$x].",";
}
}
to test the output echo it first
echo $where; //so i think the result is "action_id IN(5,9,10,21,3,18,4)"
Here is the complete code
$actionIds = array(5,9,10,21,3,18,4);
$where = "action_id IN(";
for($x=0; $x<count($actionIds); $x++)
{
// code for adding comma in every end of id
if($x==count($actionIds)-1)
{
$where.=$actionIds[$x].",";
}
else
{
// add closing parenthesis in IN funtion
$where.=$actionIds[$x].")";
}
}
$actionsTb = Engine_Api::_()->getDbtable('actions','activity');
$postSelect = $actionsTb->select()
->where($where)
->where('type = ?', 'status')
;

I don't know zend coding but following approach may help you.
->where( 'FIND_IN_SET( action_id, ? )', $actionIds )
I am not sure if zend's where converts the array $actionIds to be linear item values i.e. '5,9,10,21,3,18,4'. If converted, part of the resulting query would look like:
where find_in_set( action_id, '5,9,10,21,3,18,4' )
Example:
mysql> select find_in_set( 18, '5,9,10,21,3,18,4' );
+---------------------------------------+
| find_in_set( 18, '5,9,10,21,3,18,4' ) |
+---------------------------------------+
| 6 |
+---------------------------------------+
1 row in set (0.00 sec)
Reference:
Read MySQL documentation on FIND_IN_SET

Related

How to stop ordering CONCAT REGEXP MySQL

I have the following code which force me to order values from lowest to highest.
$values = '4|2|7|1|20';
$test = $db->QueryFetchArrayAll("SELECT id FROM user WHERE (CONCAT(',', id, ',') REGEXP ',($values),')");
foreach ($test as $test_as) {
echo $test_as['id'].',';
}
// Output:
1,2,4,7,20
// Should be same as string values:
4,2,7,1,20
How I can stop ordering it by default and make by values order?
Add a
ORDER BY FIELD(id,4,2,7,1,20);
To your SELECT.
You still should use prepared stetement when you are4 testing.

mysqli select from two tables with one of them have multiple records

<?php
select1($conn);
function select2 ($conn,$id ,$name)
{
$stmt = $conn->prepare("SELECT def FROM define WHERE wordkey = ?");
mysqli_stmt_bind_param($stmt, 'i', $id);
$stmt->execute();
$stmt->bind_result($def);
while($stmt->fetch()) {
echo "here"; // for testing
$wordArray += $def;
//I will make a call to the js function here sending id, name and wordArray
}
//$stmt->close();
}
function select1 ($conn){
$stmt2 = $conn->prepare("SELECT id , name FROM words");
$stmt2->execute();
$stmt2->bind_result($id, $name);
while($stmt2->fetch()) {
select2 ($conn,$id ,$name);
}
}
?>
I want to ask question I have words table and def table. in def table i have multiple definitions for the same words.id. Is it possible to select them in one query statement ?
words table have id , name
def table have id, wordkey , definition
I want to retrieve name and for each name select all its definitions so that I will then call a javascript function (id, name, defArray)
to display each name with the array of its definitions.
I thought of doing it through 2 select statement, but the problem is the select2 function is not working.
As I can assume from the very limited details from your question.
Try
select a.name, b.definition from words a, def b where a.id=b.word_id
In the above query we are simply accessing the data from multiple tables.
Please supply some more explanation (possibly with code) for precise bug fixings.
Hope it helps, All the best!
Assuming the following:
words
ID | Word
definitions
ID | WordID | Definition
SELECT D.Definition AS definition, W.Word AS word
FROM definitions D, words W
WHERE W.ID = D.WordID
ORDER BY W.Word ASC
This will display rows of definitions, ordered by the word they correspond to.

Selecting multiple substrings from a field in MySQL

I have a field that is a longtext in MySQL. I'm looking for any instances of 'media' that could be in it, +/- ~10 characters of context. There are usually multiple instances in a single rows' field, so I need to see the context. How can I write a query to do this? I can't even think of where to start.
So what I'm looking at is this:
SELECT field_data_body FROM table WHERE field_data_body LIKE '%media%';
+----------------------------------+
| field_data_body |
+----------------------------------+
| ... ode__media_or ... e immediat |
+----------------------------------+
The field is actually a long string, and I just parsed the actual test value to show the substrings that would match the WHERE clause.
What I actually want to see is all instances of the string media, which in the example above is two, but in other fields could be more. SUBSTR only shows the first instance of media.
CREATE FUNCTION of your own. Inside the function you can use the WHILE statement and general string functions such as LOCATE and SUBSTRING.
Here is an example to get you started:
DELIMITER $$
CREATE FUNCTION substring_list(
haystack TEXT,
needle VARCHAR(100)
)
RETURNS TEXT
DETERMINISTIC
BEGIN
DECLARE needle_len INT DEFAULT CHAR_LENGTH(needle);
DECLARE output_str TEXT DEFAULT '';
DECLARE needle_pos INT DEFAULT LOCATE(needle, haystack);
WHILE needle_pos > 0 DO
SET output_str = CONCAT(output_str, SUBSTRING(haystack, GREATEST(needle_pos - 10, 1), LEAST(needle_pos - 1, 10) + needle_len + 10), '\n');
SET needle_pos = LOCATE(needle, haystack, needle_pos + needle_len);
END WHILE;
RETURN output_str;
END$$
DELIMITER ;
Here are some tests. For each match, the term ("media") and up to 10 characters on either side are returned, all concatenated in a single string:
SELECT substring_list('1234567890media12345678immediate34567890media1234567890', 'media');
+---------------------------+
| 1234567890media12345678im |
| 12345678immediate34567890 |
| te34567890media1234567890 |
+---------------------------+
SELECT substring_list('0media12345678immediate34567890media1', 'media');
+---------------------------+
| 0media12345678im |
| 12345678immediate34567890 |
| te34567890media1 |
+---------------------------+
In mysql you can create a user define function for this like wordcount. You can get help from this UDF.
mysql count word in sql syntax
Here is a solution using PHP that will return each row and each result plus the surrounding characters in a multidimensional array.
$value = "media";
$surroundingChars = 5;
$strlen = strlen($value);
$stmt = $pdo->prepare("SELECT field_data_body FROM table WHERE field_data_body LIKE ?";
$stmt->execute([ '%'.$value.'%' ]);
$result = 0;
while ($body = $stmt->fetchColumn()) {
$start = 0;
while (($pos = stripos($body, $value, $start)) !== FALSE) {
$return[$result][] = substr($body, $pos - $surroundingChars, $strlen + ($surroundingChars * 2));
// Adjust next start
$start = $pos + $strlen;
}
$result++;
}
You could always change the $return[$result][] line, but to echo all rows in the format you wanted, you could do this:
foreach($return as $row) {
echo implode('..', $row);
}
As you stated in the comments, you'd rather a query, but if you change your mind, here is a solution matching your PHP requirements.

MySQL order by IN array

I have a MySQL script like this: SELECT id, name FROM users WHERE id IN (6,4,34)
The sequence in the IN(...) array is very important. Is it possible to get them in the given sequence?
You can use the MySQL FIELD function to keep it compact;
SELECT id, name
FROM users
WHERE id IN (6, 4, 34)
ORDER BY FIELD(id, 6, 4, 34);
Try
SELECT id, name FROM users WHERE id IN (6,4,34) order by FIELD(id,6,4,34)
You can use any expression in the ORDER BY clause, including a 'CASE':
ORDER BY CASE id
WHEN 6 THEN 1
WHEN 4 THEN 2
WHEN 34 THEN 3
END ASC
If your list comes from the application programming layer, you might build this with the following (PHP here):
$sortVal = 1;
foreach($ids as $id_val) {
$cases[] = sprintf('WHEN %i THEN %i', $id_val, $sortVal++);
}
$order_by = 'ORDER BY CASE id ' . implode($cases) . ' END ASC';
However, I'll mention that Joachim's answer is quite elegant :-)
A complete example based on Chris Trahey answer.
$ids = array("table1", "table2", "table3");
$sortVal = 1;
foreach ($ids as $id_val) {
$cases[] = sprintf("WHEN '%s' THEN %u ", $id_val, $sortVal++);
}
$order_by = 'ORDER BY CASE `tableName` ' . implode($cases) . ' END ASC';
$result = mysqli_query( $con, "
SELECT DISTINCT tableName
FROM `table`
$order_by");

mySQL: get hash value for each row?

Currently I'm manually creating a string where I concatenate all the values in each row in my table. I'm hashing this string for each row to get a hash value for the current values (/status) of the row, which I'm later is using to determine if the row has changed.
Instead of doing this manually, is there an build-in way i mySQL to get a unique hash value for each row?
you could do something like
SELECT MD5(concat(field1, field2, field3, ...)) AS rowhash
but you can't get away from listing which fields you want, as concat(*) is not an option (syntax error).
It's better to use concat_ws(). e.g. two adjacent column: 12,3 => 1,23 .
Sorry, this still has some problems. Think about the null value, empty string, string can contain ',', etc...
A program is required to generate the hash statement, which should replace null to specific value (for null-able columns), and also use the seldom used char/byte as separator.
There are problems with CONCAT, e.g. CONCAT('ab', 'c') vs CONCAT('a', 'bc'). Two different rows, but result is the same. You could use CONCAT_WS(';', 'ab', 'c') to get ab;c but in case of CONCAT_WS(';', ';', '') vs CONCAT_WS(';', '', ';') you still get the same result.
Also CONCAT(NULL, 'c') returns NULL.
I think the best way is to use QUOTE:
SELECT MD5(CONCAT(QUOTE(c1), QUOTE(c2), QUOTE(c3))) AS row_hash FROM t1;
Result of: select (concat(quote('a'), quote('bc'), quote('NULL'), quote(NULL), quote('\''), quote('')));
is: 'a''bc''NULL'NULL'\''''
Also, don't use GROUP_CONCAT() to get hash of table, it has limit: https://dev.mysql.com/doc/refman/8.0/en/server-system-variables.html#sysvar_group_concat_max_len
Instead, CHECKSUM TABLE might be better, but you can't skip columns with CHECKSUM TABLE https://dev.mysql.com/doc/refman/5.7/en/checksum-table.html
Well I made a little script that could do excactly what you want, and maybe what others want... so here it goes...for PHP that is...
first you have to make a list of columns of the table, then you make a "case when" statement for each column based on their type and put that in the concat_ws statement and then you hash it with sha1...i've used this method on very large tables (600000+ records) and the speed is quite good when selecting all records. also I think that it is faster to concat the required data in a concat_ws and explode it in php or whatever you are using, but that is just a hunch...
<?
$query= mysql_query("SHOW COLUMNS FROM $table", $linklive);
while ($col = mysql_fetch_assoc($query)) {
$columns[] = mysql_real_escape_string($col['Field']);
if ($col['Key'] == 'PRI') {
$key = mysql_real_escape_string($col['Field']);
}
$columnsinfo[$col['Field']] = $col;
}
$dates = array("date","datetime","time");
$int = array("int","decimal");
$implcols = array();
foreach($columns as $col){
if(in_array($columnsinfo[$col]['Type'], $dates)){
$implcols[] = "(CASE WHEN (UNIX_TIMESTAMP(`$col`)=0 || `$col` IS NULL) THEN '[$col EMPTY]' ELSE `$col` END)";
}else{
list($type, $rest) = explode("(",$columnsinfo[$col]['Type']);
if(in_array($columnsinfo[$col]['Type'], $dates)){
$implcols[] = "(CASE WHEN ( `$col`=0 || `$col` IS NULL ) THEN '[$col EMPTY]' ELSE `$col` END)";
}else{
$implcols[] = "(CASE WHEN ( `$col`='' || `$col` IS NULL ) THEN '[$col EMPTY]' ELSE `$col` END)";
}
}
}
$keyslive = array();
//echo "SELECT $key SHA1(CONCAT_WS('',".implode(",", $columns).")) as compare FROM $table"; exit;
$q = "SELECT $key as `key`, SHA1(CONCAT_WS('',".implode(", ",$implcols).")) as compare FROM $table";
?>