GROUP CONCAT REPLACE sep strings - mysql

I am using the below statement to pull a unique value off a table from a field that is separated with "|". It looks like this: "40|180|408|360|40|1s66|80|59" My problem is that I can't seem to get this statement to allow me to pull a primary key field, id, and assign it to each unique item from the field string so I can actually use it later. Ideally, ID # 27 should be assigned to each of the values on this temp table from "40|180|408|360|40|1s66|80|59". Can anyone help with the below statement to allow me to insert and assign field id to this from table BlogImageBundle?
CREATE TEMPORARY TABLE test (postId INT(11), val CHAR(255));
SET #S1 = CONCAT("INSERT INTO test (val) VALUES ('",REPLACE((SELECT GROUP_CONCAT( DISTINCT `images`)
AS data FROM `BlogImageBundle`), "|", "'),('"),"');");
PREPARE stmt1 FROM #s1;
EXECUTE stmt1;
SELECT DISTINCT(val) FROM test;

This works but ONLY for one record. You will need to add another while loop that keeps track of the rowcount to deal with multiple records : http://sqlfiddle.com/#!6/d62f7/1
CREATE TABLE #Test
(
ID INT,
Initial VARCHAR(MAX)
)
CREATE TABLE #Test2
(
ID INT,
Final VARCHAR(MAX)
)
INSERT INTO #Test VALUES(27,'40|180|408|360|40|1s66|80|59')
DECLARE #String VARCHAR(MAX)
SET #string = (SELECT Initial FROM #Test)
DECLARE #StringInput VARCHAR(MAX)
SET #stringInput = (SELECT Initial FROM #Test)
WHILE LEN(#StringInput) > 0
BEGIN
SET #String = LEFT(#StringInput,ISNULL(NULLIF(CHARINDEX('|', #StringInput) - 1, -1),LEN(#StringInput)))
SET #StringInput = SUBSTRING(#StringInput,ISNULL(NULLIF(CHARINDEX('|', #StringInput), 0),LEN(#StringInput)) + 1, LEN(#StringInput))
INSERT INTO #Test2 (ID, Final)
SELECT ID,#string FROM #Test
END

Related

How to join two table with JSON data id with another table column id

SELECT * FROM `preference` JOIN contact_preference ON preference.id IN (JSON_EXTRACT(contact_preference.preference_ids,'$')) WHERE contact_preference.contact = 'blahblah.com'
O/p
["Y2NuYW"]
["X8AHZg", "yhTq0w"]
Need
"X8AHZg", "yhTq0w"
so, i can search this in IN paramters
For MySQL version 5.7, you can try this solution:
See db<>fiddle
-- Your Data
CREATE TABLE jsontable AS
SELECT '["X8AHZg", "yhTq0w"]' AS json FROM dual;
-- Solution Starts Here
CREATE TABLE main_table (
value VARCHAR(1000)
);
-- 1. create procedure
CREATE PROCEDURE proc1()
BEGIN
SET #index := 0;
SELECT #jsonlength := MAX(JSON_LENGTH(json)) FROM jsontable;
REPEAT
INSERT INTO main_table (value)
SELECT JSON_EXTRACT(json,CONCAT("$[",#index,"]")) FROM jsontable;
SET #index = #index + 1;
UNTIL #index = #jsonlength
END REPEAT;
END;
-- 2. call procedure
CALL proc1;
-- 3. query result
SELECT DISTINCT REPLACE(value, '"', '') AS value
FROM main_table
In short, You can replace your query from this
JSON_EXTRACT(contact_preference.preference_ids,'$')
to this query after running the procedure
SELECT DISTINCT REPLACE(value, '"', '') AS value
FROM main_table

Alias a mysql table for a session?

I know you can give an alias to a table for a query, like SELECT 1 FROM table AS t but is there a way to give an alias to a table for a session?
The use case is I have a "query pattern" that should apply to 3 different tables. So I would like to make only one query, using a table alias, and then tell mysql "Execute this query considering that is alias is table1, then execute the same query considering the alias is table2,..."
The use case:
INSERT INTO aliasedTable (id, value) VALUES (1,1)
The tables
CREATE TABLE table1 (id INT UNSIGNED, value TINYINT UNSIGNED)
CREATE TABLE table2 (id INT UNSIGNED, value TINYINT UNSIGNED)
CREATE TABLE table3 (id INT UNSIGNED, value TINYINT UNSIGNED)
The "supposed" syntax
ALIAS table1 AS aliasedTable;
INSERT INTO aliasedTable (id, value) VALUES (1,1)
ALIAS table2 AS aliasedTable;
INSERT INTO aliasedTable (id, value) VALUES (1,1)
ALIAS table3 AS aliasedTable;
INSERT INTO aliasedTable (id, value) VALUES (1,1)
What I thought of, is making a updatable VIEW of the table, but there is no such thing like CREATE TEMPORARY VIEW .... And using a CREATE TEMPORARY TABLE aliasedTable AS (SELECT * FROM table1) would create a table copy, instead of inserting in the original table.
Any suggestion?
Note that I have such case in a PHP code, but also in a procedure:
<?php
$query = 'INSERT INTO aliasedTable (id, value) VALUES (1,1)';
foreach (array('table1', 'table2', 'table3') AS $t) {
// Ideally, I would like to avoid string concat here and tell MySQL
// something like 'ALIAS :placeholder AS aliasedTable', ['placeholder' => $t]
$pdo->query('ALIAS ' . $table1 . ' AS aliasedTable');
$pdo->query($query);
}
or
SET #tables := '["table1","table2","table3"]';
SET #i := JSON_LENGTH(#tables) - 1;
WHILE (#i >= 0) DO
SET #table := JSON_UNQUOTE(JSON_EXTRACT(#tables, CONCAT('$[', #i, ']')));
ALIAS #table AS aliasedTable;
CALL inserting();
SET #i := #i - 1;
END WHILE;
where
CREATE PROCEDURE inserting()
BEGIN
INSERT INTO aliasedTable (id, value) VALUES (1, 1);
END$$
One thing that you could do is switch to a dynamic SQL statement and pass the table name as an input argument to the inserting function:
CREATE PROCEDURE inserting( IN tbl_name VARCHAR(25) )
BEGIN
SET #stmt = CONCAT('INSERT INTO ', tbl_name, ' (id, value) VALUES (1, 1)');
PREPARE stmt FROM #stmt;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END
Depending on your call this will insert data to appropriate table. As an example:
CALL inserting('table1');
will execute following statement:
INSERT INTO table1 (id, value) VALUES (1,1);
Then from PHP you could call this procedure for each element in your array passing the current element as an argument to the function.

SELECTing the column names for another SELECT - possible?

I have a table t1 with a 'foo' column, and records containing 'bar' and 'baz' in column 'foo'. I also have a table t2 with columns 'bar', 'baz' and 'quux'. I want to do something like the following:
SELECT (SELECT foo from t1) FROM t2;
that is, get the two column names from t1 and query those columns of t2. If I try to do this with MonetDB, I get an error message:
cardinality violation (2>1)
so,
is there some other way to do this with MonetDB?
is this possible in MySQL? other DBMSes?
Example queries (or non-query directives followed by a query) are welcome.
first you need to select the columns into a variable and then use that variable to get tables
something like the following (it is not the actual implementation)
declare #colname varchar(250)
select #colname=foo from t1
select #colname from t2
this may be help.
This is how you can accomplish it in SQL Server
-- Create #T1 which contains names of columns and #T2 which contains the actual columns
CREATE TABLE #T1(colname nvarchar(max))
INSERT INTO #T1 (colname) VALUES ('b')
INSERT INTO #T1 (colname) VALUES ('c')
CREATE TABLE #T2(a int IDENTITY(1,1), b DATETIME DEFAULT GETDATE(), c NVARCHAR(max) DEFAULT 'blah')
INSERT INTO #T2 DEFAULT VALUES
INSERT INTO #T2 DEFAULT VALUES
INSERT INTO #T2 DEFAULT VALUES
--#dSQL will contain the actual SQL string to be executed
DECLARE #dSQL nvarchar(max) = ' '
SELECT #dsql = CONCAT(#dsql,'[',colname,'],') FROM #T1
SELECT #dsql = CONCAT('SELECT',LEFT(#dsql,LEN(#dsql)-1),' FROM #T2')
--You can see the SQL query being executed
PRINT #dsql
--Actually execute it
exec sp_executesql #dsql
MS Sql dynamic sql example.
create table t1(foo varchar(100))
insert t1(foo)
values('bar,baz');
create table t2(bar int, baz int)
insert t2 (bar, baz)
values
(1,100),
(3,300);
declare #cmd varchar(max);
select #cmd= 'select '+ (select top(1) foo from t1) + ' from t2';
EXEC (#cmd);
Result
bar baz
1 1 100
2 3 300
Or may be foo contains column names in different rows, not exactly clear from your question.
create table t1(foo varchar(100))
insert t1(foo)
values('bar'),('baz');
create table t2(bar int, baz int)
insert t2 (bar, baz)
values
(1,100),
(3,300);
declare #cmd varchar(max);
select #cmd= 'select '+ stuff((select ','+ foo from t1 for xml path('')),1,1,'') + ' from t2';
EXEC (#cmd);

Returning the column name(s) where a search term is found, using PHP

Example: I have a table with 5 fields, named id, field_1, field_2, field_3, field_4
And I am searching for 'foo' across all fields.
SELECT ID FROM table WHERE field_1 LIKE ('%foo%') OR field_2 LIKE ('%foo%') OR ...
I'd like to return the IDs, as well as which fields the term was found in.
What would be the most efficient way to do this?
Note: I am looking for a solution that could dynamically accommodate adding new DB fields, without having to manually update the SQL.
One possible approach is to map these matches in returned columns:
SELECT ID,
field_1 LIKE '%foo%' AS field_1_match,
field_2 LIKE '%foo%' AS field_2_match
...
... so you can just check each corresponding column_match value to know, well, was it matched or not.
It's easy to extend this into returning a string with columns (separated by ,, for example) with CONCAT_WS:
SELECT ID,
CONCAT_WS(',',
IF(field_1 LIKE '%foo%', 'field_1', NULL),
IF(field_2 LIKE '%foo%', 'field_2', NULL)
...
)
... but, honestly speaking, I doubt it'll be easier to process data formatted this way.
Use unions:
SELECT id, 'field_1' as 'fieldName' FROM table WHERE field1 LIKE '%foo%' UNION
SELECT id, 'field_2' as 'fieldName' FROM table WHERE field2 LIKE '%foo%' UNION
...
This will return the id and column name wherever it is found. If it happens multiple times on the same row, multiple results will be returned for that row.
Updated:
It is possible to dynamically search all of the tables using a stored procedure and a cursor.
DELIMITER //
CREATE PROCEDURE search_all_fields(IN search VARCHAR(100), IN tableName VARCHAR(100), IN idColumnName VARCHAR(100))
BEGIN
DECLARE sqlQuery VARCHAR(200);
DECLARE done INT DEFAULT 0;
DECLARE columnName VARCHAR(30);
DECLARE cur CURSOR FOR SELECT `COLUMN_NAME` FROM `INFORMATION_SCHEMA`.`COLUMNS` WHERE `TABLE_NAME`= tableName; # cursor will iterate over the column names
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
CREATE TEMPORARY TABLE temp ( id VARCHAR(100), FieldName VARCHAR(100) ); # procedure returns multiple result sets, so we'll dump them in a temp table and get them at the end
OPEN cur;
read_loop: LOOP # iterates through column names
FETCH cur INTO columnName;
IF done THEN
LEAVE read_loop;
END IF;
# execute search
SET #sqlQuery = CONCAT("INSERT INTO temp SELECT ", idColumnName, ", '", columnName, "' as 'FieldName' FROM ", tableName, " WHERE ", columnName, " LIKE '%", search, "%'");
PREPARE stmt FROM #sqlQuery;
EXECUTE stmt;
END LOOP;
CLOSE cur;
# grab the results
SELECT * FROM temp;
END;//
DELIMITER ;

Dynamic insert into variable table statement SQL Server

I have a variable table:
DECLARE #A_Table TABLE(ID INT, att1 VARCHAR(100), att2 nvarchar(200))
I want to make dynamic sql, so I insert into this table some data (all inside a loop):
WHILE (#i <= 100) BEGIN
SELECT #other_att = NAME FROM #other_Table where ID = #i;
SET #sql = 'INSERT ' + #A_Table+ '(ID,att1,att2) SELECT '+CAST(#i AS VARCHAR)+' , '''+ #other_att+''', SUM('+ #other_att') FROM '+ #EVEN_OTHER_Table;
EXEC (#sql);
END
sql every time would look like:
INSERT INTO #A_Table SELECT 1 , 'subject', SUM(subject)
INSERT INTO #A_Table SELECT 2 , 'age', SUM(age)
INSERT INTO #A_Table SELECT 3 , 'sex', SUM(sex)....
AND after executing this :
SO I will get:
#A_Table:
id att1 att2
1 subject 4.3
2 age 4.5
3 sex 4.1
but I get an error:
Msg 137, Level 16, State 1, Line 48
Must declare the scalar variable "#A_Table".
SO what is it the syntax to insert dynamically into a variable table?
Ok I have understood it.
You could use the INSERT ... EXEC syntax to insert the data returned by the dynamic SELECT. Of course, you would then need to remove the INSERT part from the dynamic statement.
WHILE (#i <= 100) BEGIN
SELECT #other_att = NAME FROM #other_Table where ID = #i;
SET #sql = 'SELECT '+CAST(#i AS VARCHAR)+' , ''' + #other_att+''', SUM('+ #other_att + ') FROM '+ #EVEN_OTHER_Table;
INSERT INTO #A_Table (ID,att1,att2)
EXEC (#sql);
END
You have a table variable, not a variable that contains the table name.
So you would need the following.
WHILE (#i <= 100) BEGIN
SELECT #other_att = NAME FROM #other_Table where ID = #i;
SET #sql = 'INSERT INTO #A_Table (ID,att1,att2) SELECT '+CAST(#i AS VARCHAR)+' , '''+ #other_att+''', SUM('+ #other_att') FROM #EVEN_OTHER_Table';
EXEC (#sql);
END
You would also need to declare the table variable as a statement inside the #sql variable, and execute your declare table and inserts together, or use a local/global temporary table.
With a local temporary table (stored in the tempdb) you could do something like this.
CREATE TABLE #testtbl (ID INT);
EXEC ('INSERT INTO #testtbl VALUES (1)');
SELECT * FROM #testtbl
DROP TABLE #testtbl
Some good info about temporary tables in BOL
http://msdn.microsoft.com/en-us/library/ms174979.aspx - quite far down the page
And the table type.
http://msdn.microsoft.com/en-us/library/ms175010.aspx
Your EXEC statement occurs in a different context and is therefore unaware of any variables created in your original context.
To create dynamic insert query it is really a task, I also struggle to find it ,finally I have tried in the following way and it's successfully working. Please find the code below.
CREATE PROCEDURE [dbo].[InsertTodaysData] (#tbl varchar(50),#Days int,
#MDate varchar(50), #EValue varchar(50), #Speed varchar(50),
#Totalreturn varchar(50),#Closingv varchar(50), #TotalReturnV varchar(50))
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
DECLARE #SQLQuery varchar(2000)
-- Insert statements for procedure here
set #SQLQuery = 'INSERT INTO '+#tbl+' (ID,MDate,EValue,Speed,TotalReturnRatio,ClosingValue,
TotalReturnValue) VALUES ('+#Days+','''+#MDate+''', '+#EValue+', '+#Speed+',
'+#Totalreturn+', '+#Closingv+', '+#TotalReturnV+')'
EXECUTE(#SQLQuery)
END
Hope this will help you..