Checking existence in mysql query with CASE statement - mysql

I am using CASE statement in mysql query and I have to check if a column exists or not in the same query.
Is it possible to do so? If yes please help.
My query as example -
SELECT
CASE column1
WHEN 'status' THEN 'status'
WHEN 'value' THEN
(select CASE id
WHEN id IS NOT NULL THEN 'status1' ELSE 'status2'
END AS ScheduleStatus
from table1
where condition )
END AS Status
FROM table2
LEFT JOIN table1
ON ...
WHERE condition ..;
In above query, when execute it I am getting the result "status2" (else part) even if he condition satisfy.
If the "id" row does not exists at that time the result should be "status1".
Please correct me.

see the third answer in that page -
if not exists (select
column_name
from
INFORMATION_SCHEMA.columns
where
table_name = 'MyTable'
and column_name = 'MyColumn')
it should also work in mySql.
Or you can try this one -
SELECT *
FROM information_schema.COLUMNS
WHERE
TABLE_SCHEMA = 'dbName'
AND TABLE_NAME = 'tableName'
AND COLUMN_NAME = 'columnName'
If you want to chack this inside the CASE, do it with a FUNCTION that gets varchar - the column name and return '' or NULL if the column is not exists.
replace the column name with the function-
CREATE FUNCTION Func_Check_Exists(columnName CHAR(20))
RETURNS CHAR(20)
DETERMINISTIC
BEGIN
RETURN ...;
END;
in you code -
SELECT CASE Func_Check_Exists('column1') WHEN 'status' THEN ...

Related

How find an value in to all table postgress

Suppose to have this word 'student' , I need to return all tables that contains the 'student' word. I need something like this:
select *
from information_schema.tables t
where column ='student';
Anyone can help me?
If you want tables, you would use:
select *
from information_schema.tables t
where table_name like '%student%';
If you want columns, you would use the right metadata table and use:
select *
from information_schema.columns c
where column_name like '%student%';
So you want to find the string 'students' or any version thereof in the database. Well there is no simple query that will give you that. So what you need to to select from the information schema all columns names having a string type definition and with those build a query for every column. The routine to do that is not overly complex or large providing you need only standard columns types. That no user defined types, no JSON(B), XML, or hstore types. You can try:
do $$
declare
k_sql_base constant text = $stmt$
select '%1$s' table_schema,'%2$s' table_name,'%3$s' column_name
from %1$I.%2$I where lower(%3$I) like '%4$s' limit 1;
$stmt$;
k_search_text text = '%students%';
c_text_cols cursor for
select col.table_schema
, col.table_name
, col.column_name
from information_schema.columns col
where col.data_type in ('text', 'character varying')
and col.table_schema not in ('pg_catalog', 'information_schema');
l_table_rec record;
l_search_stmt text;
begin
for l_table_rec in c_text_cols
loop
l_search_stmt = format(k_sql_base
,l_table_rec.table_schema
,l_table_rec.table_name
,l_table_rec.column_name
,k_search_text
) ;
execute l_search_stmt into l_table_rec;
if l_table_rec.table_schema is not null then
raise notice 'Found in: %.%.%',l_table_rec.table_schema
,l_table_rec.table_name
,l_table_rec.column_name;
end if;
end loop;
end;
$$;

MySQL check table exists with IF function

SELECT IF((
SELECT COUNT(TABLE_NAME)
FROM information_schema.tables
WHERE TABLE_SCHEMA='database0' AND TABLE_NAME='table'
) >0 , (
SELECT id
FROM database1.table
WHERE id NOT IN (SELECT id FROM database0.table)
), NULL) AS pk_value;
The table database0.table may not exist; if the table does not exist, I want to skip the true clause of the IF statement. Even when the IF statement should return NULL, I get the error that database0.table does not exist. What can I do so that the query returns NULL instead of throwing an error if the table does not exist?
As mentioned in comments, queries are error-checked before they are run, so referring to a non-existent table won't work. You can store it as a function, which is only evaluated at run-time:
DROP FUNCTION IF EXISTS get_pk;
DELIMITER //
CREATE FUNCTION get_pk()
RETURNS INT
BEGIN
DECLARE counter INT;
DECLARE pk_value INT;
SELECT COUNT(table_name) INTO counter
FROM information_schema.tables
WHERE table_schema = 'database0' AND table_name = 'table';
IF counter = 1 THEN
SELECT id INTO pk_value
FROM database1.table
WHERE id NOT IN (SELECT id FROM database0.table);
ELSE
SELECT NULL INTO pk_value;
END IF;
RETURN pk_value;
END//
DELIMITER ;
Then access the value like this:
SELECT get_pk();

traverse through the table and update columns with Null values

Iam working on MYSQL and need a stored procedure that will traverse through table A which has 100 columns and 50,000+ rows and for all Null values found in the table the SP will update it with blank values.
eg
UPDATE table A SET column1=' ' where column1 IS NULL;
column1 is mixture of null and filled and blank rows,but i want to update only null rows.
I do not want to hardcode the column names..want to fetch the columns one by one in the stored procedure itself.is this possible?
You could dynamically fetch the column names from your tables.
SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = 'my_database' AND TABLE_NAME = 'my_table';
And combine this using inner queries.
Use the mysql ifnull function.You will need the below for all hundred columns. This can be used on string/char as well as integer fields.
update table
set
field1=ifnull(field1, " "),
field2=ifnull(field2, " "),
field3=ifnull(field3, 0),
field4=ifnull(field4, "")....
If you don't want to hardcode the column names, you can build the above query as per the other answer:
SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = 'my_database' AND TABLE_NAME = 'my_table';
For each of the above rows, build a concatenated update statement.
DEClARE usercursor CURSOR FOR
SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = 'my_database' AND TABLE_NAME = 'my_table';
declare updatesql varchar(3000);
set updatesql = "update TABLE set ";
OPEN usercursor
get_users:LOOP
FETCH usercursor into v_username;
set updatesql = concat(v_username,"=ifnull(",updatesql)
set updatesql = concat(v_username,",' '),",updatesql)
END LOOP get_users

Chaining SQL queries

Right now I'm running
SELECT formula('FOO') FROM table1
WHERE table1.foo = 'FOO' && table1.bar = 'BAR';
but I would like to run this not on the constant FOO but on each value from the query
SELECT foos FROM table2
WHERE table2.bar = 'BAR';
How can I do this?
Edit: Important change: added FOO to the arguments of function.
Illustration:
SELECT foo FROM table1 WHERE foo = 'FOO' && table1.bar = 'BAR';
gives a column with FOOa, FOOb, FOOc.
SELECT formula('FOO') FROM table1
WHERE table1.foo = 'FOO' && table1.bar = 'BAR';
gives a single entry, say sum(FOO) (actually much more complicated, but it uses aggregates at some point to combine the results).
I want some query which gives a column with sum(FOO1), sum(FOO2), ... where each FOOn is computed in like manner to FOO. But I'd like to do this with one query rather than n queries (because n may be large and in any case the particular values of FOOn vary from case to case).
Try this one:
SELECT formula FROM table1
WHERE table1.foo IN(SELECT foos FROM table2
WHERE table2.bar = 'BAR';
) AND table1.bar = 'BAR';
SELECT formula FROM table1 WHERE bar = 'BAR' AND foo IN (SELECT foos FROM table2 WHERE bar = 'BAR');
EDIT:
This isn't tested, but perhaps this will work?
SELECT formula(q1.foo) FROM table1 INNER JOIN (SELECT foo, bar FROM table2) q1 ON table1.foo = q1.foo WHERE table1.bar = 'BAR';
You will have to use dynamic SQL statements.
The way this works is that you just string the SQL statement together using parameters.
You will need to be careful though not to allow users to feed that data, because escaping cannot protect you against SQL-injection. You will need to check every column name against a whitelist.
Here's example code in a stored procedure.
The way this works, is that you have a (temporary) table with column names and the stored procedure builds this into a query:
dynamic /*holds variable parts of an SQL statement
-----------
id integer PK
column_name varchar(255)
operation ENUM('what','from','where','group by','having','order by','limit')
function_name varchar(255) /*function desc with a '#' placeholder where */
/* the column-name goes */
whitelist /*holds all allowed column names*/
-----------
id integer PK
allowed varchar(255) /*allowed column of table name*/
item ENUM('column','table')
Dynamic SQL stored procedure. Expects two tables: dynamic and whitelist to be prefilled.
DELIMITER $$
CREATE PROCEDURE dynamic_example;
BEGIN
DECLARE vwhat VARCHAR(65000);
DECLARE vfrom VARCHAR(65000);
DECLARE vwhere VARCHAR(65000);
DECLARE vQuery VARCHAR(65000);
SELECT group_concat(REPLACE(function_name,'#',column_name)) INTO vwhat
FROM dynamic
INNER JOIN whitelist wl ON (wl.allowed LIKE column_name
AND wl.item = 'column')
WHERE operation = 'what' AND
SELECT group_concat(REPLACE(function_name,'#',column_name)) INTO vfrom
FROM dynamic
INNER JOIN whitelist wl ON (wl.allowed LIKE column_name
AND wl.item = 'table')
WHERE operation = 'from';
SELECT group_concat(REPLACE(function_name,'#',column_name)) INTO vwhere
FROM dynamic
INNER JOIN whitelist wl ON (wl.allowed LIKE column_name
AND wl.item = 'column')
WHERE operation = 'where';
IF vwhat IS NULL THEN SET vwhat = ' * ';
IF vwhere IS NOT NULL THEN SET vwhere = CONCAT(' WHERE ',vwhere); END IF;
SET vQuery = CONCAT(' SELECT ',vwhat,' FROM ',vfrom,IFNULL(vwhere,''));
PREPARE dSQL FROM vQuery;
EXECUTE dSQL;
DEALLOCATE PREPARE dSQL;
END $$
DELIMITER ;
Try:
SELECT formula FROM table1, table2
WHERE table1.foo = table2.foo AND table1.bar = table2.bar;

How to check if an index exists on a table field in MySQL

How do I check if an index exists on a table field in MySQL?
I've needed to Google this multiple times, so I'm sharing my Q/A.
Use SHOW INDEX like so:
SHOW INDEX FROM [tablename]
Docs: https://dev.mysql.com/doc/refman/5.0/en/show-index.html
Try:
SELECT * FROM information_schema.statistics
WHERE table_schema = [DATABASE NAME]
AND table_name = [TABLE NAME] AND column_name = [COLUMN NAME]
It will tell you if there is an index of any kind on a certain column without the need to know the name given to the index. It will also work in a stored procedure (as opposed to show index)
show index from table_name where Column_name='column_name';
SHOW KEYS FROM tablename WHERE Key_name='unique key name'
will show if a unique key exists in the table.
Use the following statement:
SHOW INDEX FROM *your_table*
And then check the result for the fields: row["Table"], row["Key_name"]
Make sure you write "Key_name" correctly
To look at a table's layout from the CLI, you would use
desc mytable
or
show table mytable
Adding to what GK10 suggested:
Use the following statement: SHOW INDEX FROM your_table
And then check the result for the fields: row["Table"],
row["Key_name"]
Make sure you write "Key_name" correctly
One can take that and work it into PHP (or other language) wrapped around an sql statement to find the index columns. Basically you can pull in the result of SHOW INDEX FROM 'mytable' into PHP and then use the column 'Column_name' to get the index column.
Make your database connection string and do something like this:
$mysqli = mysqli_connect("localhost", "my_user", "my_password", "world");
$sql = "SHOW INDEX FROM 'mydatabase.mytable' WHERE Key_name = 'PRIMARY';" ;
$result = mysqli_query($mysqli, $sql);
while ($row = $result->fetch_assoc()) {
echo $rowVerbatimsSet["Column_name"];
}
Try to use this:
SELECT TRUE
FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE
WHERE TABLE_SCHEMA = "{DB_NAME}"
AND TABLE_NAME = "{DB_TABLE}"
AND COLUMN_NAME = "{DB_INDEXED_FIELD}";
You can use the following SQL to check whether the given column on table was indexed or not:
select a.table_schema, a.table_name, a.column_name, index_name
from information_schema.columns a
join information_schema.tables b on a.table_schema = b.table_schema and
a.table_name = b.table_name and
b.table_type = 'BASE TABLE'
left join (
select concat(x.name, '/', y.name) full_path_schema, y.name index_name
FROM information_schema.INNODB_SYS_TABLES as x
JOIN information_schema.INNODB_SYS_INDEXES as y on x.TABLE_ID = y.TABLE_ID
WHERE x.name = 'your_schema'
and y.name = 'your_column') d on concat(a.table_schema, '/', a.table_name, '/', a.column_name) = d.full_path_schema
where a.table_schema = 'your_schema'
and a.column_name = 'your_column'
order by a.table_schema, a.table_name;
Since the joins are against INNODB_SYS_*, the match indexes only came from the INNODB tables only.
If you need to check if a index for a column exists as a database function, you can use/adopt this code.
If you want to check if an index exists at all regardless of the position in a multi-column-index, then just delete the part AND SEQ_IN_INDEX = 1.
DELIMITER $$
CREATE FUNCTION `fct_check_if_index_for_column_exists_at_first_place`(
`IN_SCHEMA` VARCHAR(255),
`IN_TABLE` VARCHAR(255),
`IN_COLUMN` VARCHAR(255)
)
RETURNS tinyint(4)
LANGUAGE SQL
DETERMINISTIC
CONTAINS SQL
SQL SECURITY DEFINER
COMMENT 'Check if index exists at first place in sequence for a given column in a given table in a given schema. Returns -1 if schema does not exist. Returns -2 if table does not exist. Returns -3 if column does not exist. If index exists in first place it returns 1, otherwise 0.'
BEGIN
-- Check if index exists at first place in sequence for a given column in a given table in a given schema.
-- Returns -1 if schema does not exist.
-- Returns -2 if table does not exist.
-- Returns -3 if column does not exist.
-- If the index exists in first place it returns 1, otherwise 0.
-- Example call: SELECT fct_check_if_index_for_column_exists_at_first_place('schema_name', 'table_name', 'index_name');
-- check if schema exists
SELECT
COUNT(*) INTO #COUNT_EXISTS
FROM
INFORMATION_SCHEMA.SCHEMATA
WHERE
SCHEMA_NAME = IN_SCHEMA
;
IF #COUNT_EXISTS = 0 THEN
RETURN -1;
END IF;
-- check if table exists
SELECT
COUNT(*) INTO #COUNT_EXISTS
FROM
INFORMATION_SCHEMA.TABLES
WHERE
TABLE_SCHEMA = IN_SCHEMA
AND TABLE_NAME = IN_TABLE
;
IF #COUNT_EXISTS = 0 THEN
RETURN -2;
END IF;
-- check if column exists
SELECT
COUNT(*) INTO #COUNT_EXISTS
FROM
INFORMATION_SCHEMA.COLUMNS
WHERE
TABLE_SCHEMA = IN_SCHEMA
AND TABLE_NAME = IN_TABLE
AND COLUMN_NAME = IN_COLUMN
;
IF #COUNT_EXISTS = 0 THEN
RETURN -3;
END IF;
-- check if index exists at first place in sequence
SELECT
COUNT(*) INTO #COUNT_EXISTS
FROM
information_schema.statistics
WHERE
TABLE_SCHEMA = IN_SCHEMA
AND TABLE_NAME = IN_TABLE AND COLUMN_NAME = IN_COLUMN
AND SEQ_IN_INDEX = 1;
IF #COUNT_EXISTS > 0 THEN
RETURN 1;
ELSE
RETURN 0;
END IF;
END$$
DELIMITER ;
You can't run a specific show index query because it will throw an error if an index does not exist. Therefore, you have to grab all indexes into an array and loop through them if you want to avoid any SQL errors.
Heres how I do it. I grab all of the indexes from the table (in this case, leads) and then, in a foreach loop, check if the column name (in this case, province) exists or not.
$this->name = 'province';
$stm = $this->db->prepare('show index from `leads`');
$stm->execute();
$res = $stm->fetchAll();
$index_exists = false;
foreach ($res as $r) {
if ($r['Column_name'] == $this->name) {
$index_exists = true;
}
}
This way you can really narrow down the index attributes. Do a print_r of $res in order to see what you can work with.