MySQL: "SELECT text as <HERE A VARIABLE OR SUBQUERY> FROM ......." - mysql

I have the following Table with the following Data inside:
id
text
lanuage
1
deutscher text
german
2
english text
english
What I want is to get the Result in the following Format:
german="deutscher text"
english="english text"
This menas, it should be not:
text="deutscher text"
text="english text"
The Key/Column Name text should be the data from language
I tried the following Query but its not working:
SELECT text as (SELECT language FROM `table` where id = 1) FROM `table` where id = 1;
(SELECT language FROM table where id = 1) will return "german" so the Query should be:
"SELECT text as german FROM table where id = 1;" but this is not working.
Is there a way to do this in one Query?
Cheers, Thomas

One option you can use is PREPARED STATEMENT:
SET #sql := NULL;
SELECT GROUP_CONCAT(
CONCAT('MAX(CASE WHEN language="',language,'" THEN text END) AS "',language,'"'))
INTO #sql
FROM mytable;
SELECT CONCAT('SELECT ',#sql,' FROM mytable;') INTO #sql;
PREPARE stmt FROM #sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
First step is dynamically assigning columns required to the #sql variable. Then, concatenating the previously assigned #sql variable with the rest of the final SELECT query, then re-assign it to the #sql variable. The query will end up with:
SELECT MAX(CASE WHEN language="german" THEN text END) AS "german",
MAX(CASE WHEN language="english" THEN text END) AS "english"
FROM mytable;
Lastly, we prepare, execute then deallocate the statement assigned in the #sql variable and you'll get your expected result.
Demo fiddle

You'll have to alter your table schema a bit; Added a ref to group the languages to use
CREATE TABLE IF NOT EXISTS `test` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`ref` int(11) DEFAULT 0,
`text` varchar(50) DEFAULT NULL,
`language` varchar(50) DEFAULT NULL,
KEY `Index 1` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb3;
Then the SQL
SELECT T.text AS english, T2.text AS german
FROM test T
INNER JOIN test T2 ON T.ref = T2.ref AND T2.`language` = 'german'
WHERE
T.ref = 1 AND
T.language = 'english'
The dummy data
INSERT INTO `test` (`id`, `ref`, `text`, `language`) VALUES
(1, 1, 'deutscher text', 'german'),
(2, 1, 'english text', 'english');

Related

Using the input parameters from stored parameters as variables inside where clause MySQL

I have a simple mysql table:
CREATE TABLE `cont` (
`ID` int(11) NOT NULL,
`Meeting_id` int(11) DEFAULT NULL,
`member_name` varchar(20) NOT NULL,
`cont_prod` varchar(20) NOT NULL,
`start_date` date NOT NULL,
`type_of` varchar(100),
`ord_qty` int(11) DEFAULT NULL
) ;
I am trying to dynamically transpose rows to columns following this example enter link description here
In side the SELECT STATEMENT when I use the input parameters inside WHERE clause it is giving me error column not found.
I tried to declare the variable as :
SET #v1 = c_prod;
SET #v2 = s_date;
and teh in the where clause:
WHERE cont_prod = #v1 AND start_date = #v2
it is still not working
How can I define the input parameter variable inside the WHERE clause?
Any help would be highly apprecuited.
BEGIN
SET #sql = NULL;
SELECT
GROUP_CONCAT(DISTINCT
CONCAT(
'max(case when type_of = '',
type_of,
'' then ord_qty end) ',
type_of
)
) INTO #sql
FROM
cont
where cont_prod = c_prod AND start_date = s_date;
SET #sql = CONCAT('SELECT product_id,member_name,start_date,cont_prod, ', #sql, '
FROM cont WHERE cont_prod = c_prod AND start_date = s_date
GROUP BY member_name,cont_prod,start_date');
PREPARE stmt FROM #sql;
EXECUTE st......
Use ? to specify parameters in the prepared statement, and pass the parameters on the EXECUTE line.
SET #sql = CONCAT('SELECT product_id,member_name,start_date,cont_prod, ', #sql, '
FROM cont WHERE cont_prod = ? AND start_date = ?
GROUP BY member_name,cont_prod,start_date');
PREPARE stmt FROM #sql;
EXECUTE stmt USING c_prod, s_date;

How to group concat multiple record by id passed separated by comma in stored procedure?

The below is the query which i am using to get generated multiple formula based on the group concat, so the i can apply the same formula on different table. its working fine for single id by not working for comma separated id
/*id_val = '6,7'; //pased in sp paramter */
SET #query = (SELECT GROUP_CONCAT(CONCAT('(SUM(',column_name_table,') / sum(count_of_x) ) * 100
as ',kpi_display_name,' ') ) FROM `formula_table` WHERE id IN (id_val) );
SELECT #query;
Where count_of_x is static value; column_name_table is the field in formula_table
but the above query return single value;
table structure as
CREATE TABLE `formula_table` (
`id` int NOT NULL AUTO_INCREMENT,
`column_name_table` varchar(255) DEFAULT NULL
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=84 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
insert into `formula_table`(`id`,`column_name_table`) values
(5,'higest_record'),
(6,'higest_salary'),
(7,'higest_employee'),
(9,'higest_x');
I Have try this problem is resolved
SET #g_formula = "";
SET #query = CONCAT(' select group_concat(column_table_name) into #g_formula from (
select concat("(sum(",column_table_name,")/","sum(count_of_x)) * 100 as ",column_table_name) as column_table_name
from (
select column_table_name from formula_table
where id in (',id_val,')
) as aa ) as bb
');
SELECT #query;
PREPARE stmt FROM #query;
EXECUTE stmt;
SELECT #g_formula;

Pivot Table in Mysql with a lot of dynamic columns

I have problems in makeing a PIVOT Table in MySQL. I have following table. (it is a reduced demo table. The real one has 4000 stocks for f.e 10 tradedates and 20 measurement values.)
CREATE TABLE `levermann` (
`RecNum` bigint(20) NOT NULL AUTO_INCREMENT,
`Tradedate` date DEFAULT NULL,
`Stock_Short` varchar(50) DEFAULT NULL,
`Country` varchar(2) DEFAULT NULL,
`LScore2` int(11) DEFAULT NULL,
`MarketCAPUSD` bigint(20) DEFAULT NULL,
PRIMARY KEY (`RecNum`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of levermann
-- ----------------------------
INSERT INTO `levermann` VALUES ('8099', '2018-05-23', 'ANDR.VI', 'VI', '-9', '5109518494');
INSERT INTO `levermann` VALUES ('8100', '2018-05-23', 'BWO.VI', 'VI', '-7', '4241189324');
INSERT INTO `levermann` VALUES ('8101', '2018-05-23', 'CAI.VI', 'VI', '-7', '3222135865');
INSERT INTO `levermann` VALUES ('8102', '2018-05-09', 'CWI.VI', 'VI', '-8', null);
INSERT INTO `levermann` VALUES ('8103', '2018-05-23', 'EBS.VI', 'VI', '-7', '18317742129');
INSERT INTO `levermann` VALUES ('8104', '2018-05-23', 'FLU.VI', 'VI', '-8', '3176359049');
INSERT INTO `levermann` VALUES ('8105', '2018-05-23', 'IIA.VI', 'VI', '-8', '2767477473');
INSERT INTO `levermann` VALUES ('8106', '2018-05-23', 'LNZ.VI', 'VI', '-9', '3027507195');
The output should be a table where each STOCKCODE (f.e. ANDR.VI) of these 8 should be a column with one selectable measurement value (f.e. LScore2) grouped by tradedate (= row).
I have found this Exmapl in MYSQL but I do not understand it completely. More over I have done this:
SELECT
tradedate,
GROUP_CONCAT(stock_short) as STOCKCODE
FROM
levermann
GROUP BY
Tradedate;
But here the stockcodes are in one cell and not in the header.
Here is an image of an example of the wanted output. The total number of columns are about 4000 (max columns in table do not exceed 4096). And the tradedates (= rows) are about 350 days / years for 2 years in total.
It sheems clear that the columns should be created dynamically and can not hardcoded by AS statements.
Is there any solution for this difficult question?
THANKS a lot.
Update:
I think on a dynamically running statement like this..
SET #sql = NULL;
SELECT GROUP_CONCAT(concat(LScore2,' AS `LScore_',Stock_Short,'`')) into
#sql from levermann;
SET #sql = CONCAT('SELECT tradedate, ', #sql, '
FROM levermann
GROUP BY tradedate');
PREPARE stmt FROM #sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
But I do not know how I can create the string:
LScore AS LScore_ANDR.VI, LScore AS LScore_BWO.VI, ...
I really in doubt but it might be done in a way in MySQL.
Of course I can make a php script too. But I would like to learn how it is done in MySQL.
Update 2: I think I could make it. I am not quite sure if it is correct, but it is dynamically created. In MySQL
I think I have got it:
SET SESSION group_concat_max_len = ##max_allowed_packet;
SET #sql = NULL;
SELECT GROUP_CONCAT(concat('MAX(CASE Stock_Short WHEN \'',Stock_Short,'\' THEN \'',LScore2,'\' END) AS `LScore_',Stock_Short,'`')) into #sql from levermanndemo where country = 'VI';
SET #sql = CONCAT('SELECT tradedate, ', #sql, '
FROM levermanndemo
GROUP BY tradedate');
PREPARE stmt FROM #sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
OUTPUT:
Update: Unfortunatly it makes troubel if the table looks like this.
I tried this solution:
SET SESSION group_concat_max_len = ##max_allowed_packet;
SET #sql = NULL;
SELECT GROUP_CONCAT( DISTINCT concat('MAX(CASE WHEN p.Stock_Short =
\'',f.Stock_Short,'\' AND `Tradedate` = \'', f.tradedate,'\' THEN
\'',f.LScore2,'\' ELSE NULL END) AS `LScore_',f.Stock_Short,'`'))
into #sql from levermanndemo f ;
SET #sql = CONCAT('SELECT p.tradedate, ', #sql, ' FROM levermanndemo p
GROUP BY p.tradedate');
#SELECT #sql;
PREPARE stmt FROM #sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
The output is not desired - and wrong. There are now 2 columns with the same STOCK (BWO.VI and BWO.VI1) , I would like to merge these two columns together. But how can it be done?
In SQL, you can't write any query that expands columns dynamically based on the data values it finds once it starts reading data. All the columns must be fixed in the query's select-list at the time you prepare the query -- before it reads any data.
This means you must know all the distinct values, and you need to produce a select-list with one column for each value you want to include in the pivot.
You can solve this by doing two queries: one to fetch all the distinct stock values:
SELECT DISTINCT Stock_Short FROM levermann
Then based on that result, format a looooong SQL query with on expression for each stock value. Start with the column you know you want that is not one of the dynamic stock-related columns:
SELECT Tradedate,
Then for each row in the result from the firs query, append a column like:
MAX(CASE Stock_Short WHEN <value> THEN LScore2 END) AS <alias>,
Then finally append the end of the query:
FROM levermann
GROUP BY Tradedate;
My recommendation since you have 4000 distinct stock values is that you should just fetch the data from the database as-is, and use application code to present a pivoted display. That is, loop over the result of the SQL query, all 4000 rows (not columns), and arrange it into an object in your application space. Then format that object however you want for display.
If the list of StockCodes is fixed can one not simply fix the columns of the new table and then filter for the data in the original table to copy into the new table?
At least this would be the process when doing it manually in Excel for instance.

How can I implement an SQL query that starting from a query returning multiple records return a single records with multiple columns?

I am not so into database and I have the following problem working on a MySql database.
I have a table like this:
CREATE TABLE CommodityName (
id BigInt(20) NOT NULL AUTO_INCREMENT,
commodity_details_id BigInt(20) NOT NULL,
language_id BigInt(20) NOT NULL,
commodity_name VarChar(255) CHARACTER SET latin1 COLLATE latin1_swedish_ci NOT NULL,
description Text CHARACTER SET latin1 COLLATE latin1_swedish_ci,
PRIMARY KEY (
id
)
) ENGINE=InnoDB AUTO_INCREMENT=87 ROW_FORMAT=DYNAMIC DEFAULT CHARACTER SET latin1 COLLATE latin1_swedish_ci;
ALTER TABLE CommodityName COMMENT = '';
The records in this table represents commodities information in different languages.
The commodity is specified by the univocally by the commodity_details_id (that is a FK of another table).
A specific commodity can have multiple record into this CommodityName table (I have a record for each translation in a specific language, represented by the language_id field). For example I have these 2 records:
id commodity_details_id language_id commodity_name description
-------------------------------------------------------------------------------------------------------
1 1 1 Rice Asia Rice Asia
16 1 3 Umuceli Asia Umuceli Asia
that represents the same commodities information (both having commodity_details_id=1) but in 2 languages (English and Kinirwanda language). In theory I can have also other languages, so I can have n records for a specific commodity.
I need to create a query where for a specified commodity (WHERE commodity_details_id=1) it returns all the commodity_name fields of the retrieved record as column of a single record.
Referring to the previous example something like this:
commodity_details_id commodity_name_EN commodity_name_RWA commodity_name_FR
----------------------------------------------------------------------------------------------------------------
1 Rice Asia Umuceli Asia null
How can I implement a query like this that from multiple records transform a part of the information in each records as a new column in the new query?
Try This:
SELECT commodity_details_id,
MAX(CASE WHEN language_id=1 then commodity_name else null END) commodity_name_EN,
MAX(CASE WHEN language_id=3 then commodity_name else null END) commodity_name_RWA,
MAX(CASE WHEN language_id=2 then commodity_name else null END) commodity_name_FR
FROM CommodityName
group by commodity_details_id;
What you are looking for is called Dynamic Pivot.
Look at the below code and see if it works for you. Schema might be little different in your case(just names of columns and tables).
I am using commodityName, commodity_details, languages table.
All you need to do is pass a commodity_details_id in parameter at 2nd line:
SET #sql = NULL;
SET #commodity_details_id = 1;
SELECT
GROUP_CONCAT(DISTINCT
CONCAT(
'max(CASE WHEN language_id = ''',
ID,
''' then ''',
(select commodity_name from commodityname where language_id = L.Id and commodity_details_id = #commodity_details_id),
''' end) AS ',
Concat('Commodity_Name','_', language_name)
)
) INTO #sql
from languages L;
SET #sql = CONCAT(
'SELECT commodity_details_id, '
, #sql,
'
FROM CommodityName
where commodity_details_id = ',#commodity_details_id,'
group by commodity_details_id;
');
PREPARE stmt FROM #sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
You can also create a stored routine out of this to call it from application or something.
Please comment if it doesn't work for you.

Use sql result to specify table to join

Is there any way how can I use result for specifying table to join?
I'd like to do something like
SELECT id, some_number, ... FROM sometable NATURAL JOIN someothertable_$some_number;
I know that there's nothing like this in relational algebra, so probably I'll not succeed, I just wanted to ask to be sure.
I don't want to use any SQL scripts.
Runnable Example Here: http://sqlfiddle.com/#!2/5e92c/36
Code to setup tables for this example:
create table if not exists someTable
(
someTableId bigint not null auto_increment
, tableId int not null
, someOtherTableId bigint not null
, primary key (someTableId)
, index (tableId, someOtherTableId)
);
create table if not exists someOtherTable_$1
(
someOtherTableId bigint not null auto_increment
, data varchar(128) character set utf8
, primary key (someOtherTableId)
);
create table if not exists someOtherTable_$2
(
someOtherTableId bigint not null auto_increment
, data varchar(128) character set utf8
, primary key (someOtherTableId)
);
insert sometable (tableId, someOtherTableId) values (1, 1);
insert sometable (tableId, someOtherTableId) values (1, 2);
insert sometable (tableId, someOtherTableId) values (2, 2);
insert sometable (tableId, someOtherTableId) values (2, 3);
insert someothertable_$1(data) values ('table 1 row 1');
insert someothertable_$1(data) values ('table 1 row 2');
insert someothertable_$1(data) values ('table 1 row 3');
insert someothertable_$2(data) values ('table 1 row 1');
insert someothertable_$2(data) values ('table 1 row 2');
insert someothertable_$2(data) values ('table 1 row 3');
STATIC SOLUTION
Here's a solution if your tables are fixed (e.g. in the example you only have someOtherTable 1 and 2 / you don't need the code to change automatically as new tables are added):
select st.someTableId
, coalesce(sot1.data, sot2.data)
from someTable st
left outer join someOtherTable_$1 sot1
on st.tableId = 1
and st.someOtherTableId = sot1.someOtherTableId
left outer join someOtherTable_$2 sot2
on st.tableId = 2
and st.someOtherTableId = sot2.someOtherTableId;
DYNAMIC SOLUTION
If the number of tables may change at runtime you'd need to write dynamic SQL. Beware: with every successive table you're going to take a performance hit. I wouldn't recommend this for a production system; but it's a fun challenge. If you can describe your tool set & what you're hoping to achieve we may be able to give you a few pointers on a more suitable way forward.
select group_concat(distinct ' sot' , cast(tableId as char) , '.data ')
into #coalesceCols
from someTable;
select group_concat(distinct ' left outer join someOtherTable_$', cast(tableId as char), ' sot', cast(tableId as char), ' on st.tableId = ', cast(tableId as char), ' and st.someOtherTableId = sot', cast(tableId as char), '.someOtherTableId ' separator '')
into #tableJoins
from someTable;
set #sql = concat('select someTableId, coalesce(', #coalesceCols ,') from someTable st', #tableJoins);
prepare stmt from #sql;
execute stmt;