convert dynamically the rows to columns with out specifying fields - mysql

How can I convert dynamically a key-value table using Case without specifying row names?
For example I have this table named key_value:
id key value
1 name john
2 fname akbar
3 jobs Software enginer
. . .
. . .
. . .
. . .
. . .
n n n
I want to convert all these rows dynamically to columns without specifying key name like:
name fname jobs............................n
john akbar sofware engineer...........n
I have used:
Max(Case WHEN key='name' THEN value END) AS name
In this query I know my key.
What if I don't know my fields and I don't know how many fields I have?
I want to convert all of this dynamically without specifying my fields.

This was also my question way back
SQL Query fields as columns
I modified it to answer yours and I hope it helps just like it did to me!
SET #sql = NULL;
SELECT
GROUP_CONCAT(DISTINCT
CONCAT(
'MAX(IF(a.xvalue = ''',
xvalue,
''', a.xvalue, NULL)) AS ',
xkey
)
) INTO #sql
FROM key_value;
SET #sql = CONCAT('SELECT ', #sql, '
FROM key_value a
LEFT JOIN key_value AS b
ON a.id=b.id');
PREPARE stmt FROM #sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
SQL Fiddle

Related

How to pivot columns to rows in MySQL for N number of columns without using Union all

I already went through the details in the link (Mysql Convert Column to row (Pivot table )). As the number of Columns is high and using union all on all of them would be time taking. I decided to use the last resolution in the given link. I was able to run the query the results were:
The issue is the acct getting included as data and also I want to create a table from the result . So Can these entries be excluded and how can I create a table from the results? (new to SQL)
The Code:
SET SESSION group_concat_max_len = 92160;
SET #target_schema='rd';
SET #target_table='pbc_gl';
SET #target_where='`acct`';
SELECT
GROUP_CONCAT(qry SEPARATOR ' UNION ALL ')
INTO #sql
FROM (
SELECT
CONCAT('SELECT `acct`,', QUOTE(COLUMN_NAME), ' AS `Business_Unit`,`', COLUMN_NAME, '` AS `value` FROM `', #target_table, '` WHERE ', #target_where) qry
FROM (
SELECT `COLUMN_NAME`
FROM `INFORMATION_SCHEMA`.`COLUMNS`
WHERE `TABLE_SCHEMA`=#target_schema
AND `TABLE_NAME`=#target_table
) AS `A`
) AS `B` ;
PREPARE s FROM #sql;
EXECUTE s;
DEALLOCATE PREPARE s;

Create an insert to pivot value pair values into a table

I have a value pair table that I want to use to create a member table
Based on Taryns answer to this question
MySQL pivot table query with dynamic columns
I have this code that creates selects the data, which works fine
SELECT
GROUP_CONCAT(DISTINCT
CONCAT(
'MAX(CASE WHEN wpdg_usermeta.meta_key = ''',
meta_key,
''' THEN wpdg_usermeta.meta_value END) `',
meta_key, '`'
)
) INTO #sql
FROM
wpdg_usermeta
WHERE
wpdg_usermeta.meta_key like "member_%"
;
SET #sql = CONCAT('SELECT user_id, ', #sql, '
FROM wpdg_usermeta
GROUP BY user_id');
PREPARE stmt FROM #sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
So, my question is - does anyone know how I could alter this to run an INSERT instead of a SELECT so that I could populate the new member table?
You want to create a new table with the results of the dynamic query. I think the simplest approach is to use the create table ... as select ... syntax.
This requires very few changes to your code, and allow you to create the table on the fly based on the results of the query:
SET #sql = CONCAT(
'CREATE TABLE member AS SELECT user_id, ',
#sql,
' FROM wpdg_usermeta GROUP BY user_id'
);
Note that the datatypes of the new table are inferred from the query's metadata; this might, or might no, to exactly what you want. You can check the documentation for more detaiils.

Error on dynamic column headers with mySQL

This question in regarding mySQL.
I am reading data from an .csv file that looks like this
original table
------------------------------------
Id 2018M01 2018M02 2018M03
------------------------------------
EMEA 3 1 4
ASPAC 4 5 4
ASPAC 1 2 1
expected result
---------------------
ID Month Qty
---------------------
EMEA 2018M01 3
EMEA 2018M02 1
EMEA 2018M03 4
ASPAC 2018M01 4
.......
The months column header are dynamic, that is each month there will be new months and old months will be removed. However the total number of columns will remain the same.
Hence whenever the month columns headers change I would like the SQL code to dynamically read and provide correct results without me having to manually change several parts of the code.
I have written the following code; Code is to unpivot the month columns. However I tested the code by manually making changes to the .csv file headers by changing 2018M03 to 2018M04, and rerunning the SQL code, but it still seems to print the old data . What am I doing wrong ?
Thank you. I am fairly new to SQL.
DROP TABLE IF EXISTS book;
CREATE TABLE book (
ID VARCHARACTER(10),
2018M01 decimal(4,2),
2018M02 decimal(4,2),
2018M03 decimal(4,2)
);
LOAD DATA LOCAL INFILE '/Users/blytonpereira/Desktop/Book1.csv' REPLACE INTO TABLE book
FIELDS TERMINATED BY ',' LINES TERMINATED BY '\n' IGNORE 1 LINES;
DESCRIBE book;
SELECT ID, '2018M01' AS month, 2018M01 AS qty from book
UNION ALL
SELECT ID, '2018M02' AS month, 2018M02 AS qty from book
UNION ALL
SELECT ID, '2018M03' AS month, 2018M03 AS qty from book;
SET #sql = NULL;
SELECT
GROUP_CONCAT(DISTINCT
CONCAT(
'select ID, ''',
c.column_name,
''' AS month, ',
c.column_name,
' as qty
from book
where ',
c.column_name,
' > 0'
) SEPARATOR ' UNION ALL '
) INTO #sql
FROM information_schema.columns c
where c.table_name = 'book'
and c.column_name not in ('id')
order by c.ordinal_position;
SET #sql
= CONCAT('select id, month, qty
from
(', #sql, ') x order by id');
PREPARE stmt FROM #sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
);
** Updated answer:
This solution is dynamic, whatever columns you have in table, it will populate them and extract information in required format. For sure columns have to have something in common, like they're all begins with "2018", you can change that as needed in Query.
SELECT
GROUP_CONCAT(
CONCAT(
'SELECT id, ''', COLUMN_NAME, ''' as month, ', COLUMN_NAME, ' as QTY FROM t1 ') SEPARATOR ' UNION ALL ')
FROM
`INFORMATION_SCHEMA`.`COLUMNS`
WHERE
`COLUMN_NAME` LIKE '2018%'
INTO #sql;
SET #query = CONCAT('select id, month, QTY from (' , #sql , ') x order by id;');
SELECT #query;
PREPARE stmt FROM #query;
EXECUTE stmt;
**Note: the query has 2 outputs, first is the prepared concatenated query string (just to know what it looks like before run), and the other is the actual data. If you want only actual data you can comment (SELECT #query;) or remove it.

Mysql transpose complex sql query table dynamically

I have a table with two columns, following is the schema:
create table scan( `application_name` varchar(255) NOT NULL, `defect_type` varchar(255) NOT NULL);
And the data is populated accordingly. The table stores data for "Application" and its corresponding "Defect Type". I want to perform following 2 actions on this table:
Get the Top 3 "Defect Type" of a particular application in terms of percent.
Transpose the output from above where the values in "Defect Type" (defect_type) become the columns and its corresponding percent (finalPercent) as the its value.
I am able to achieve 1, following is the SQL Fiddle:
SQLFiddle
However, I am not able to transpose the output as per the requirement. Ideally there should be a single row as follows after both 1 & 2 together:
application_name | CrossSide | CSS | XML
A | 33.33 | 33.33 | 16.67
Thank you!
You can build a dynamic pivot query with group_concat and then execute it:
set #sql = null;
set #total = (select count(*) as totalcount from scan where application_name = "a");
select group_concat(distinct
concat(
'round(((count(case when defect_type = ''',
defect_type,
''' then application_name end)/ #total ) * 100 ), 2) as `',
defect_type, '`'
)
) into #sql
from ( select defect_type
from scan
where application_name = "a"
group by defect_type
order by count(defect_type) desc
limit 3) t;
set #sql = concat(
'select application_name, ', #sql,
' from scan
where application_name = "a"
group by application_name'
);
prepare stmt from #sql;
execute stmt;
deallocate prepare stmt;
SQLFiddle

Mysql query search a string in all columns of a table

I wonder how I can mount a SQL as portable as possible to query for all columns of a table for a specific phrase, like:
Table
ID | Name | text | Date | Author | Status
1 | Augusto Weiand | Test text | 2010-01-01 | Deividi | 1
Query
SELECT *
FROM table
WHERE columns LIKE '%augusto%2010%text%"
I did not put enough detail, excuse me, I like to make a dynamic SQL, where I do not need to specify the columns with 'AND' or 'OR', as it is possible to do in Postgres:
Select *
From table
Where table::text ~~ '%augusto%2010%text%'
Here is how you would concatenate the values in dynamic SQL:
set #Pattern = '%augusto%';
select #q := concat('select * from Table1 ',
'where concat(', group_concat(column_name), ', "") like "', #Pattern, '"'
)
from information_schema.columns c
where table_name = 'Table1';
prepare st from #q;
execute st;
deallocate prepare st;
Of course, dynamic SQL is not particularly portable. The idea would work in most databases. The code would look different.
Tested and working here.
And finally, you can do this with variable substitution (which is the better approach):
select #q := concat('select * from Table1 ',
'where concat(', group_concat(column_name), ', "") like ?'
)
from information_schema.columns c
where table_name = 'Table1';
set #p = '%augusto%';
prepare st from #q;
execute st using #p;
deallocate prepare st;
Also tested (;-).
It's doable, although I strongly suggest you look into full-text search for efficiency;
To avoid looking for all patterns in all fields one by one, you can just concat and search in that;
SELECT *
FROM (SELECT id,CONCAT(name,'|',text,'|',date,'|',author,'|',status) txt
FROM Table1) a
WHERE txt LIKE '%augusto%'
AND txt LIKE '%2010%'
AND txt LIKE '%text%';
Note that no indexing will help you here, since you're searching in a calculated column. On the other hand, since you're searching with a leading wildcard %searchterm, you won't get much help from indexes even if searching field by field :)
An SQLfiddle to test with.
try this
Select * FROM table WHERE text LIKE "%text%"
OR date LIKE "%2010%"
OR Name LIKE "%augusto%"
if you want them all together then use AND
Select * FROM table WHERE text LIKE "%text%"
AND date LIKE "%2010%"
AND Name LIKE "%augusto%"
you can use this store procedure to search a text in all column in table
CREATE PROCEDURE dbo.sp_FindStringInTable #stringToFind VARCHAR(100),
#schema
sysname, #table sysname
AS
BEGIN TRY
DECLARE #sqlCommand varchar(max) = 'SELECT * FROM [' + #schema + '].[' +
#table + '] WHERE '
SELECT #sqlCommand = #sqlCommand + '[' + COLUMN_NAME + '] LIKE ''' +
#stringToFind + ''' OR '
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_SCHEMA = #schema
AND TABLE_NAME = #table
AND DATA_TYPE IN ('char','nchar','ntext','nvarchar','text','varchar')
SET #sqlCommand = left(#sqlCommand,len(#sqlCommand)-3)
EXEC (#sqlCommand)
PRINT #sqlCommand
END TRY
BEGIN CATCH
PRINT 'There was an error. Check to make sure object exists.'
PRINT error_message()
END CATCH
Execute it like this
EXEC sp_FindStringInTable '%searchword%','schema_name', 'tablename'