Skipping a query field on IF condition - mysql

My MySQL query is sent to a csv, and then to a HTML file.
When I do...
SELECT
field_a,
IF($VAR="yes",field_b,""),
field_c
FROM table
INTO OUTFILE "query.csv";
...I always get 3 columns (field_a, field_b or empty, field_c), as expected.
How can I get only 2 columns (field_a, field_c) when $VAR is not "yes"?

Build your query dynamically. It looks like your $VAR condition does not depend on the data. Then you may do this (example in PHP):
$fields = 'field_a' ;
if ($VAR == 'yes') $fields .= ', field_b' ; // and so on
$query = "SELECT $fields FROM table" ;

Related

Mysql - select all columns of a single row with its values and column comments

Here is the query to get all columns of a single row
$STH = $DBH->db->prepare("SELECT * FROM Settings");
$STH->execute();
$STH->setFetchMode(PDO::FETCH_ASSOC);
$str = '';
while ($row = $STH->fetch())
{
foreach($row as $key => $value)
{
$str .= '<div>'.$key.' => '.$value.'</div>';
}
}
and this one is to get extended information of the column (including comment)
$STH = $DBH->db->prepare("SHOW FULL COLUMNS FROM Settings");
$STH->execute();
$STH->setFetchMode(PDO::FETCH_ASSOC);
\* the same php code *\
can I combine these two SQL queries to get the following data simultaniously
`FieldName`, `FieldValue`, `CommentValueOfColumn`
'
'
'
example of Settings table
Columns -> | PrintImage | SettMinus | HasChat . . .
--------------------------------------------
Values -> 0 1 1 . . .
and there is additional data Comment of the column.
So I want to select data:
PrintImage, 0 , Comment of PrintImage;
SettMinus, 1 , Comment of SettMinus;
HasChat, 1 , Comment of HasChat;
.....................................
and so on.
This will give you the column name, values of the columns and the comments. However, you can use php to get the values which is
VALUEARRAY[ORDINAL_POSITION]
You also need to copy/paste the rest of the column names after concat_ws.
Again, I cannot do everything in mysql so it needs help from PHPcodes to get the exact value from the array.
SELECT s.COLUMN_NAME,
s.ORDINAL_POSITION,
t.valuearray,
s.COLUMN_COMMENT
from INFORMATION_SCHEMA.columns s
cross join (select concat_ws(",", PrintImage,
SettMinus,HasChat) as valuearray from settings) t
where s.TABLE_NAME='Settings';
sample result :
COLUMN_NAME ORDINAL_POSITION valuearray COLUMN_COMMENT
PrintImage 1 0,1,1 commenttest
SettMinus 2 0,1,1 comments too
HasChat 3 0,1,1 3rd comment

How to compare Comma Seperated value to get existing value

I have Table as Production with field name as production_code
Production_code have value like this,
Id production_code
1 P101,P102,P103,P105
2 P103,P106,P102
3 P104
4 P102,P105,P111
------ I have value on PHP page like $p_code='P102,P109';
Now I want to fetch rows from Table Production_code where any code is exist in production_code of variable $p_code
please help me .. what mysql query should i use
You can use function FIND_IN_SET, like:
SELECT * FROM yourTable
WHERE FIND_IN_SET('P102', production_code) OR FIND_IN_SET('P109', production_code)
Solution.
<?php
$p_code='P102,P109'; //example
$condition = '';
foreach(explode(',',$p_code) as $r){//explode convert $p_code string into array. then apply foreach for compare every element of array From database saved value
$condition .= 'FIND_IN_SET("'.$r.'", production_code) OR ';
}
$condition = rtrim($condition,' OR '); //this remove last occurence of OR from condition
echo $sql = 'SELECT * FROM yourTable
WHERE '.$condition;
?>

Select record using FIND_IN_SET

I am storing the check box value as comma separated value in db like
Features
1,3,4
1,2,3,4,5
3,4,5,6
Now while searching i need to select the record based on the user select the check-box, say example if user selects 1 and 6 needs to fetch matched record. I am getting selected check-box value as array like (0=>1,1=>6). I dont know how to loop through this like FIND_IN_SET(1,Features) OR FIND_IN_SET(6,Features)
It has to come like
SELECT * FROM table WHERE FIND_IN_SET(1,Features) OR FIND_IN_SET(6,Features)
$str='%';
foreach($array as $val)
{$str.=$val.'%';}
SELECT * FROM table WHERE Features like $str
Update:
$str='';
foreach($array as $val)
{$str.='or Feature like %'.$val.'%';}
$str[0]='';$str[1]='';
SELECT * FROM table WHERE $str
I fixed using the below code to get query like this SELECT * FROM table WHERE FIND_IN_SET(1,Features) OR FIND_IN_SET(6,Features)
if($selCount >1){
foreach($luxPropFeatures as $val) {
$str .="OR FIND_IN_SET('".$val."',LP.luxury_property_feature_id) ";
$trimmed = ltrim($str, "OR");
//$str[0]='';$str[2]='';
}
}else{
foreach($luxPropFeatures as $val) {
$trimmed = "FIND_IN_SET('".$val."',LP.luxury_property_feature_id) ";
}
}

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";
?>

Why doesn't this SELECT query return the results I expect?

I need help with a select query, but before asking the question, I will give a short description of how my system works:
My database has a many-to-many relationship:
table product:
prd_cod(pk) //stores the product code ex: 0,1,2
cat_cod(fk)
prd_name //stores the product name, ex: tv, gps, notebook
table description_characteristc:
prd_cod(fk)
id_characteristic(fk)
description //stores the description of the characteristic, ex: sony, 1kg, hj10
table characteristic:
id_characteristic (pk)
name_characteristic //store the name of characteristic, ex: brand, weight, model
I have already made a suggest jQuery (in the index.php), where every word I type calls suggest.php, which makes a select and returns the result into the suggestion box in the index:
<?php
header('Content-type: text/html; charset=UTF-8');
$hostname = 'localhost';
$username = 'root';
$password = '';
$dbname = 'cpd';
mysql_connect($hostname, $username, $password)or die('Erro ao tentar conecta o banco
de dados.');
mysql_select_db( $dbname );
if( isset( $_REQUEST['query'] ) && $_REQUEST['query'] != "" )
{
$q = mysql_real_escape_string( $_REQUEST['query'] );
if( isset( $_REQUEST['identifier'] ) && $_REQUEST['identifier'] == "sugestao")
{
$sql = "SELECT p.prd_name, d.description
FROM product p
INNER JOIN description_characteristc d using (prd_cod)
WHERE '".$q."' like concat(p.prd_name, '%') AND
concat(p.prd_name, ' ', d.description) like concat('".$q."', '%')LIMIT 10";
$r = mysql_query( $sql );
if ( $r )
{
echo '<ul>'."\n";
$cont = 0;
while( $l = mysql_fetch_array( $r ) ){
$p = $l['nome'];
$p = preg_replace('/(' . $q . ')/i', '<span style="font-
weight:bold;">$1</span>',
$l['prd_nome'].' '.$l['descricao'].' '.$l['descricao']);
echo "\t".'<li id="autocomplete_'.$cont.'"
rel="'.$l['prd_nome'].'.'.$l['descricao'].'">'. utf8_encode( $p ) .'</li>'."\n";
$cont++;
}
echo '</ul>';
}
}
}
?>
Here are my questions:
Currently when the user types 't', the select brings nothing, only when the user type 'tv' is bringing the result:
tv led
tv plasm
tv samsumg
I would like that when the user type 't' the select bring me 'tv'.
When you type 'tv plasm' it's bringing the same name_characteristic twice:
ex: tv plasm plasm
Currently my select selects the prd_name and the descriptions of table description_characteristc:
tv led
I would like my select could make a inverse select too, ex: led tv.
I would like that when the results of the select were shown, there could be a cache feature that shows the order of the most sought for the less sought; remembering that prd_name stores only 'tv'.
The help I'm looking for can be in the form of select, as in the form of procedure. Also, I can edit the php file.
You should split and join your search query on PHP side like this:
<?php
$words = preg_split("/[^\\w]+/", $q);
$first = $words[0] + "%";
$all = implode(" ", $words) + "%";
?>
then use the variables $first and $all in this query:
SELECT p.prd_name, d.description
FROM product p
JOIN description d
ON d.prd_cod = p.prd_cod
WHERE p.prd_name LIKE '$first'
AND CONCAT(p.prd_name, ' ', d.description) LIKE '$all'
Create an index on product (prd_name) for this to work fast.
If you want the words matched in any order, you will have to create a FULLTEXT index on your tables (this is only possible in MyISAM):
CREATE FULLTEXT INDEX fx_product_name ON product (prd_name)
CREATE FULLTEXT INDEX fx_description_name ON description (description)
and write a query like this:
SELECT p.prd_name, d.description
FROM (
SELECT prd_cod
FROM product pi
WHERE MATCH(prd_name) AGAINST ('lcd tv' IN BOOLEAN MODE)
UNION
SELECT prd_cod
FROM description di
WHERE MATCH(description) AGAINST ('lcd tv' IN BOOLEAN MODE)
) q
JOIN product p
ON p.prd_cod = q.prd_cod
JOIN description d
ON d.prd_cod= p.prd_cod
WHERE MATCH(p.prd_name, d.description) AGAINST ('+lcd +tv' IN BOOLEAN MODE)
Note the search term syntax change: 'lcd tv' in the inner query and '+lcd +tv' in the outer one.
You may also want to set ##ft_min_word_len to 1 for the shorter words like tv or gps to match.
Since MySQL cannot build a fulltext index from two or more tables at once, it would be more simple if you denormalized you tables and put the prd_name into the description table. This way, you could get rid of the joins and just write:
SELECT prd_name, description
FROM description d
WHERE MATCH(prd_name, description) AGAINST ('+lcd +tv' IN BOOLEAN MODE)
You're using the LIKE clause badly and you don't seem to know what "AND" means. It's important to separate "and" as used in casual speech from "AND" as used in programming. AND in programming means "BOTH MUST BE TRUE". "and" in casual speech can mean "one of these conditions, you know what I mean?"
Also, you shouldn't be building SQL like this, it's an accident waiting to happen. You really should find a way to bind variables into SQL statements. I don't know PHP, so I can't help with that.
First, you should be using this in your WHERE clause p.prd_name LIKE '$q%'. Try this outside PHP -- outside the web -- just as a simple SQL query: SELECT * FROM PRODUCT P WHERE P.PRD_NAME LIKE 'T%'.
Second, you should fix "AND" to be "OR", since you want one condition OR the other condition to be true. If you want for BOTH conditions to be true, hardly anything will match.