SQL joining 1 to 1 and 1 to many table [duplicate] - mysql

This question already has answers here:
How to concatenate text from multiple rows into a single text string in SQL Server
(47 answers)
Closed 7 years ago.
If I issue SELECT username FROM Users I get this result:
username
--------
Paul
John
Mary
but what I really need is one row with all the values separated by comma, like this:
Paul, John, Mary
How do I do this?

select
distinct
stuff((
select ',' + u.username
from users u
where u.username = username
order by u.username
for xml path('')
),1,1,'') as userlist
from users
group by username
had a typo before, the above works

This should work for you. Tested all the way back to SQL 2000.
create table #user (username varchar(25))
insert into #user (username) values ('Paul')
insert into #user (username) values ('John')
insert into #user (username) values ('Mary')
declare #tmp varchar(250)
SET #tmp = ''
select #tmp = #tmp + username + ', ' from #user
select SUBSTRING(#tmp, 0, LEN(#tmp))

good review of several approaches:
http://blogs.msmvps.com/robfarley/2007/04/07/coalesce-is-not-the-answer-to-string-concatentation-in-t-sql/
Article copy -
Coalesce is not the answer to string concatentation in T-SQL I've seen many posts over the years about using the COALESCE function to get string concatenation working in T-SQL. This is one of the examples here (borrowed from Readifarian Marc Ridey).
DECLARE #categories varchar(200)
SET #categories = NULL
SELECT #categories = COALESCE(#categories + ',','') + Name
FROM Production.ProductCategory
SELECT #categories
This query can be quite effective, but care needs to be taken, and the use of COALESCE should be properly understood. COALESCE is the version of ISNULL which can take more than two parameters. It returns the first thing in the list of parameters which is not null. So really it has nothing to do with concatenation, and the following piece of code is exactly the same - without using COALESCE:
DECLARE #categories varchar(200)
SET #categories = ''
SELECT #categories = #categories + ',' + Name
FROM Production.ProductCategory
SELECT #categories
But the unordered nature of databases makes this unreliable. The whole reason why T-SQL doesn't (yet) have a concatenate function is that this is an aggregate for which the order of elements is important. Using this variable-assignment method of string concatenation, you may actually find that the answer that gets returned doesn't have all the values in it, particularly if you want the substrings put in a particular order. Consider the following, which on my machine only returns ',Accessories', when I wanted it to return ',Bikes,Clothing,Components,Accessories':
DECLARE #categories varchar(200)
SET #categories = NULL
SELECT #categories = COALESCE(#categories + ',','') + Name
FROM Production.ProductCategory
ORDER BY LEN(Name)
SELECT #categories
Far better is to use a method which does take order into consideration, and which has been included in SQL2005 specifically for the purpose of string concatenation - FOR XML PATH('')
SELECT ',' + Name
FROM Production.ProductCategory
ORDER BY LEN(Name)
FOR XML PATH('')
In the post I made recently comparing GROUP BY and DISTINCT when using subqueries, I demonstrated the use of FOR XML PATH(''). Have a look at this and you'll see how it works in a subquery. The 'STUFF' function is only there to remove the leading comma.
USE tempdb;
GO
CREATE TABLE t1 (id INT, NAME VARCHAR(MAX));
INSERT t1 values (1,'Jamie');
INSERT t1 values (1,'Joe');
INSERT t1 values (1,'John');
INSERT t1 values (2,'Sai');
INSERT t1 values (2,'Sam');
GO
select
id,
stuff((
select ',' + t.[name]
from t1 t
where t.id = t1.id
order by t.[name]
for xml path('')
),1,1,'') as name_csv
from t1
group by id
;
FOR XML PATH is one of the only situations in which you can use ORDER BY in a subquery. The other is TOP. And when you use an unnamed column and FOR XML PATH(''), you will get a straight concatenation, with no XML tags. This does mean that the strings will be HTML Encoded, so if you're concatenating strings which may have the < character (etc), then you should maybe fix that up afterwards, but either way, this is still the best way of concatenating strings in SQL Server 2005.

building on mwigdahls answer. if you also need to do grouping here is how to get it to look like
group, csv
'group1', 'paul, john'
'group2', 'mary'
--drop table #user
create table #user (groupName varchar(25), username varchar(25))
insert into #user (groupname, username) values ('apostles', 'Paul')
insert into #user (groupname, username) values ('apostles', 'John')
insert into #user (groupname, username) values ('family','Mary')
select
g1.groupname
, stuff((
select ', ' + g.username
from #user g
where g.groupName = g1.groupname
order by g.username
for xml path('')
),1,2,'') as name_csv
from #user g1
group by g1.groupname

You can use this query to do the above task:
DECLARE #test NVARCHAR(max)
SELECT #test = COALESCE(#test + ',', '') + field2 FROM #test
SELECT field2 = #test
For detail and step by step explanation visit the following link
http://oops-solution.blogspot.com/2011/11/sql-server-convert-table-column-data.html

DECLARE #EmployeeList varchar(100)
SELECT #EmployeeList = COALESCE(#EmployeeList + ', ', '') +
CAST(Emp_UniqueID AS varchar(5))
FROM SalesCallsEmployees
WHERE SalCal_UniqueID = 1
SELECT #EmployeeList
source:
http://www.sqlteam.com/article/using-coalesce-to-build-comma-delimited-string

In SQLite this is simpler. I think there are similar implementations for MySQL, MSSql and Orable
CREATE TABLE Beatles (id integer, name string );
INSERT INTO Beatles VALUES (1, "Paul");
INSERT INTO Beatles VALUES (2, "John");
INSERT INTO Beatles VALUES (3, "Ringo");
INSERT INTO Beatles VALUES (4, "George");
SELECT GROUP_CONCAT(name, ',') FROM Beatles;

you can use stuff() to convert rows as comma separated values
select
EmployeeID,
stuff((
SELECT ',' + FPProjectMaster.GroupName
FROM FPProjectInfo AS t INNER JOIN
FPProjectMaster ON t.ProjectID = FPProjectMaster.ProjectID
WHERE (t.EmployeeID = FPProjectInfo.EmployeeID)
And t.STatusID = 1
ORDER BY t.ProjectID
for xml path('')
),1,1,'') as name_csv
from FPProjectInfo
group by EmployeeID;
Thanks #AlexKuznetsov for the reference to get this answer.

A clean and flexible solution in MS SQL Server 2005/2008 is to create a CLR Agregate function.
You'll find quite a few articles (with code) on google.
It looks like this article walks you through the whole process using C#.

If you're executing this through PHP, what about this?
$hQuery = mysql_query("SELECT * FROM users");
while($hRow = mysql_fetch_array($hQuery)) {
$hOut .= $hRow['username'] . ", ";
}
$hOut = substr($hOut, 0, strlen($hOut) - 1);
echo $hOut;

Related

Finding duplicate values over multiple databases in MySQL

There are multiple (mysql) databases running under 1 website. 1 database per registered account.
I'm looking for duplicate records in each contacts-table.
This is what i have for finding duplicates inside only 1 database:
SELECT COUNT(contacts.email), contacts.email, contacts.state, contacts.source,
FROM shard_40000006.contacts
LEFT JOIN shard_40000006.optin ON optin.email=contacts.email
GROUP BY contacts.email
HAVING COUNT(contacts.email) > 1;
The query i need searches for duplicates over shard_40000001, shard_40000002, shard_40000003, .. shard_40999999
You can use dynamic tsql.
declare #sqltext nvarchar(max) = N''
declare #parameter varchar(max) = 'define what you want to search here'
select #sqltext += '
SELECT COUNT(contacts.email), contacts.email, contacts.state, contacts.source,
FROM '+name+'.dbo.contacts
LEFT JOIN '+name+'.dbo.optin ON optin.email=contacts.email
GROUP BY contacts.email
HAVING COUNT(contacts.email) > 1'
FROM sys.databases
WHERE OBJECT_ID(QUOTENAME(name) + '.dbo.prac_nag', 'U') IS NOT NULL -- will return only if the table exists
print #sqltext
-- once your review the output, uncomment out below
--exec sp_executesql #sqltext
I just put refernce code. i didn't test this code.

Is it possible that I could find a row contains a string? Assume that I do not know which columns contain a string

I know that there are several ways to find which row's column contains a string, like using [column name] regexp ' ' or [column name] like ' '
while currently what I need some help is I have a table with several columns, all of there are varchar or text and I am not sure which column contains a certain string. Just say that I want to search a "xxx from a table. Several different columns could contain this string or not. Is there a way that I could find which column contains this string?
I have a thinking and the solution could be
select * from [table name] where [column1] regexp 'xxx' or
[column2] regexp 'xxx' or ...... [column39] regexp 'xxx' or .....
[colum60] regexp 'xxx' or ... or [column 80] regexp 'xxx';
I do not want the query like this. Is there another effective way?
To give a better example, say that we are searching for a table that belongs to a blog.
We have title, URL, content, key words, tag, comment and so on. Now we just say, if any blog article is related to "database-normalization", this word may appear in the title, URL or content or anywhere, and I do not want to write it one by one like
where title regexp 'database-normalization' or content regexp 'database-normalization' or url regexp 'database-normalization'......
as when there are hundreds columns, I need to write a hundred, or in this case is there an effective way instead of write hundred or statement? Like using if-else or collections or some others to build the query.
If you want a pure dynamic way, you can try this. I've tried it long back on sql-server and hope it may help you.
#TMP_TABLE -- a temporary table
- PK, IDENTITY
- TABLE_NAME
- COLUMN_NAME
- IS_EXIST
INSERT INTO #TMP_TABLE (TABLE_NAME,COLUMN_NAME)
SELECT C.TABLE_NAME, COLUMN_NAME
FROM INFORMATION_SCHEMA.COLUMNS C
WHERE C.TABLE_NAME = <your-table> AND C.DATA_TYPE = 'varchar'; -- you can modify it to handle multiple table at once.
-- boundaries
SET #MINID = (SELECT ISNULL(MIN(<PK>),0) FROM #TMP_TABLE );
SET #MAXID = (SELECT ISNULL(MAX(<PK>),0) FROM #TMP_TABLE );
WHILE ((#MINID<=#MAXID) AND (#MINID<>0))
BEGIN
SELECT #TABLE_NAME = TABLE_NAME,#COLUMN_NAME = COLUMN_NAME
FROM #TMP_TABLE
WHERE <PK> = #MINID;
SET #sqlString = ' UPDATE #TMP_TABLE
SET IS_EXIST = 1
WHERE EXIST (SELECT 1 FROM '+ #TABLE_NAME+' WHERE '+ #COLUMN_NAME +' = ''demo.webstater.com'') AND <PK> = '+ #MINID;
EXEC(#sql) ;
SET #MINID = (SELECT MIN(<PK>) FROM #TMP_TABLE WHERE <PK> > #MINID );
END
SELECT * FROM #TMP_TABLE WHERE IS_EXIST = 1 ; -- will give you matched results.
If you know the columns in advance, what you proposed is probably the most effective way (if a little verbose).
Otherwise, you could get the column names from INFORMATION_SCHEMA.COLUMNS and construct dynamic SQL based on that.
His question is not to query specific columns with like clause. He has been asking to apply same pattern across columns dynamically.
Example: Table having 3 columns - FirstName, LastName, Address and pattern matching is "starts with A" then resulting query should be:
Select * From Customer where FirstName like 'A%" or LastName like 'A%" or Address like 'A%'
If you want to build query in business layer, this could easily be done with reflection along with EF.
If you are motivated to do in database then you can achieve by building query dynamically and then execute through sp_executesql.
Try this (Just pass tablename and the string to be find)-:
create proc usp_findString
#tablename varchar(500),
#string varchar(max)
as
Begin
Declare #sql2 varchar(max),#sql nvarchar(max)
SELECT #sql2=
STUFF((SELECT ', case when '+QUOTENAME(NAME)+'='''+#string+''' then 1 else 0 end as '+NAME
FROM (select a.name from sys.columns a join sys.tables b on a.[object_id]=b.[object_id] where b.name=#tablename) T1
--WHERE T1.ID=T2.ID
FOR XML PATH('')),1,1,'')
--print #string
set #sql='select '+#sql2+' from '+#tablename
print #sql
EXEC sp_executesql #sql
End
SQL Server 2014
One way is to use CASE to check the substring existence with LOCATE in mysql and return the column but all you have to check in every column of the table as below:
CREATE TABLE test(col1 VARCHAR(1000), col2 VARCHAR(1000), col3 VARCHAR(1000))
INSERT INTO test VALUES
('while currently what I need some help is I have a table with 10 columns',
'contains a certain string. Just say that I want to search a table',
'contains a certain string demo.webstater.com')
SELECT (CASE WHEN LOCATE('demo.webstater.com', col1, 1) > 0 THEN 'col1'
WHEN LOCATE('demo.webstater.com', col2, 1) > 0 THEN 'col2'
WHEN LOCATE('demo.webstater.com', col3, 1) > 0 THEN 'col3'
END) whichColumn
FROM test
OUTPUT:
whichColumn
col3
There are many ways in which you can do your analysis. You can use "LIKE A%%" if it starts from A in SQL, "REGEX" LibrarY for multiple checks.

Query to Search All possible words

I need to write a Delphi 7 and mysql database query which would return the records including ALL words in the submitted name. So query will return records which has all those name words but can have different order.
For example, if search string is John Michael Smith, query should be able to return records with names such as John Smith Michael, Michael Smith John, Smith John Michael or other combination with all those words there.
As can be seen return only records which still has all words in name field but can have different order.
I can't figure out how to write a query for such requirement that I have. Please help.
procedure Tfrm_Query.Button1Click(Sender: TObject);
var
mask : string;
begin
mask:='''%'+StringReplace(Edit1.text,' ','%',[rfReplaceAll, rfIgnoreCase])+'%''';
if Edit1.Text > '' then
begin
Adosorgulama.Close;
Adosorgulama.SQL.Clear;
Adosorgulama.SQL.Add('SELECT * FROM stok.product');
Adosorgulama.SQL.ADD('Where (P_Name like '+mask+') limit 50');
Adosorgulama.Open;
end;
end;
as a result;
edit1.text:='Jo Mich'; // Result Ok!
edit1.text:='Smi Jo Mic'; //No result
edit1.text:='Mich Sm'; // No result
Instead of replacing spaces with %, you could replace them with % AND P_Name LIKE %:
mask:='''WHERE (P_Name LIKE %'+StringReplace(Edit1.text,' ','% AND P_Name LIKE %',[rfReplaceAll, rfIgnoreCase])+'%)''';
Apologies if there is some problem with the syntax (I don't know Delphi), but if Edit1.text:= 'John Michael Smith' this should generate the following WHERE clause:
WHERE (P_Name LIKE %John% AND P_Name LIKE %Michael% AND P_Name LIKE %Smith%)
Which should find all records where P_Name contains the strings 'John', 'Michael' and 'Smith'.
Then, of course, instead of
Adosorgulama.SQL.ADD('Where (P_Name like '+mask+') limit 50');
you'd do something like
Adosorgulama.SQL.ADD(mask + ' limit 50');
If the input can contain extraneous spaces, you will need to remove those first, otherwise this won't work.
Forming SQL queries with string concatenation could make your application vulnerable to SQL injection, just so you know. I don't know how to do prepared statements with Delphi, so I can't help you there.
Write a function that can split the name according to space. Use the following code inside a loop that is looping split results.
Declare #sqlq as nvarchar(max);
-- loop start
#sqlq = sqlq + 'Select * from mytable where names';
#sqlq = sqlq + 'like ''%' + loopvalue + '%''';
--loop end
Exec #sqlq
You can build table of words dynamically. To find yours match do query that join both tables in possible match, and by grouping results test it - is name have all of words, try this:
WITH
words AS (SELECT 'John' AS word FROM dual union
SELECT 'Michael' FROM dual union
SELECT 'Smith' FROM dual ) , --build your table of words (this is example on oracle DB engine)
names AS (SELECT 'John Michael Smith' AS name FROM dual UNION
SELECT 'John SmithMichael' FROM dual union
SELECT 'Smith Michael' FROM dual union
SELECT 'Smith Michael John' FROM dual union
SELECT 'John' FROM dual union
SELECT 'John John' FROM dual union
SELECT 'John John John' FROM dual union
SELECT 'xyz abc' FROM dual ) --this is simulation of yours table of names
SELECT name, Count(DISTINCT word)
FROM names, words
WHERE ' ' || name || ' ' LIKE '% ' || word || ' %'
GROUP BY name
HAVING Count(DISTINCT word) = (SELECT Count(1) FROM words)
;
Problem is solved.
Delphi + MySQL connection with word order with the following code, regardless of calls can be made. Thank you for inspiration. Respects.
Database model;
CREATE TABLE IF NOT EXISTS `TableName` (
`ID` int(11) NOT NULL AUTO_INCREMENT,
`PNUMBER` varchar(20) DEFAULT NULL,
`PNAME` varchar(255) DEFAULT NULL,
`PBARCODE` varchar(30) DEFAULT NULL,
`PSearch` mediumtext,
PRIMARY KEY (`ID`),
FULLTEXT KEY `PSearch` (`PSearch`)
) ENGINE=MyISAM DEFAULT CHARSET=latin5 ;
Psearch = PNUMBER + PNAME + PBARCODE ...; (Type in all areas PSearch)
Delphi7 Code;
procedure TForm1.Button1Click(Sender: TObject);
var
mask : string;
begin
mask:='+'+StringReplace(Edit1.text,' ','* +',[rfReplaceAll, rfIgnoreCase])+'*';
if Edit1.Text > '' then
begin
Query1.Close;
Query1.SQL.Clear;
Query1.SQL.Add('SELECT MATCH(PSearch) AGAINST("'+mask+'" IN BOOLEAN MODE), tablename.* FROM database.tablename');
Query1.SQL.Add('WHERE MATCH(PSearch) AGAINST("'+mask+'" IN BOOLEAN MODE) limit 300;');
Query1.Open;
end; end;

splitting a row in sql with different information in sql server [duplicate]

How to split a string in SQL Server.
Example:
Input string: stack over flow
Result:
stack
over
flow
if you can't use table value parameters, see: "Arrays and Lists in SQL Server 2008 Using Table-Valued Parameters" by Erland Sommarskog , then there are many ways to split string in SQL Server. This article covers the PROs and CONs of just about every method:
"Arrays and Lists in SQL Server 2005 and Beyond, When Table Value Parameters Do Not Cut it" by Erland Sommarskog
You need to create a split function. This is how a split function can be used:
SELECT
*
FROM YourTable y
INNER JOIN dbo.yourSplitFunction(#Parameter) s ON y.ID=s.Value
I prefer the number table approach to split a string in TSQL but there are numerous ways to split strings in SQL Server, see the previous link, which explains the PROs and CONs of each.
For the Numbers Table method to work, you need to do this one time table setup, which will create a table Numbers that contains rows from 1 to 10,000:
SELECT TOP 10000 IDENTITY(int,1,1) AS Number
INTO Numbers
FROM sys.objects s1
CROSS JOIN sys.objects s2
ALTER TABLE Numbers ADD CONSTRAINT PK_Numbers PRIMARY KEY CLUSTERED (Number)
Once the Numbers table is set up, create this split function:
CREATE FUNCTION [dbo].[FN_ListToTable]
(
#SplitOn char(1) --REQUIRED, the character to split the #List string on
,#List varchar(8000)--REQUIRED, the list to split apart
)
RETURNS TABLE
AS
RETURN
(
----------------
--SINGLE QUERY-- --this will not return empty rows
----------------
SELECT
ListValue
FROM (SELECT
LTRIM(RTRIM(SUBSTRING(List2, number+1, CHARINDEX(#SplitOn, List2, number+1)-number - 1))) AS ListValue
FROM (
SELECT #SplitOn + #List + #SplitOn AS List2
) AS dt
INNER JOIN Numbers n ON n.Number < LEN(dt.List2)
WHERE SUBSTRING(List2, number, 1) = #SplitOn
) dt2
WHERE ListValue IS NOT NULL AND ListValue!=''
);
GO
You can now easily split a CSV string into a table and join on it:
select * from dbo.FN_ListToTable(' ','stack over flow')
OUTPUT:
ListValue
-------------------
stack
over
flow
(3 row(s) affected)
A common set-based solution to this kind of problem is to use a numbers table.
The following solution uses a simple recursive CTE to generate the numbers table on the fly - if you need to work with longer strings, this should be replaced with a static numbers table.
DECLARE #vch_string varchar(max)
DECLARE #chr_delim char(1)
SET #chr_delim = ' '
SET #vch_string = 'stack over flow'
;WITH nums_cte
AS
(
SELECT 1 AS n
UNION ALL
SELECT n+1 FROM nums_cte
WHERE n < len(#vch_string)
)
SELECT n - LEN(REPLACE(LEFT(s,n),#chr_delim,'')) + 1 AS pos
,SUBSTRING(s,n,CHARINDEX(#chr_delim, s + #chr_delim,n) -n) as ELEMENT
FROM (SELECT #vch_string as s) AS D
JOIN nums_cte
ON n <= LEN(s)
AND SUBSTRING(#chr_delim + s,n,1) = #chr_delim
OPTION (MAXRECURSION 0);
I know this question was for SQL Server 2008 but things evolve so starting with SQL Server 2016 you can do this
DECLARE #string varchar(100) = 'Richard, Mike, Mark'
SELECT value FROM string_split(#string, ',')
CREATE FUNCTION [dbo].[Split]
(
#List varchar(max),
#SplitOn nvarchar(5)
)
RETURNS #RtnValue table
(
Id int identity(1,1),
Value nvarchar(max)
)
AS
BEGIN
While (Charindex(#SplitOn,#List)>0)
Begin
Insert Into #RtnValue (value)
Select
Value = ltrim(rtrim(Substring(#List,1,Charindex(#SplitOn,#List)-1)))
Set #List = Substring(#List,Charindex(#SplitOn,#List)+len(#SplitOn),len(#List))
End
Insert Into #RtnValue (Value)
Select Value = ltrim(rtrim(#List))
Return
END
Create Above Function And Execute Belowe Query To Get Your Result.
Select * From Dbo.Split('Stack Over Flow',' ')
Suggestion : use delimiter for get split value. it's better. (for ex. 'Stack,Over,Flow')
Hard. Really hard - Strin Manipulation and SQL... BAD combination. C# / .NET for a stored procedure is a way, could return a table defined type (table) with one item per row.

INSERT INTO ... SELECT without detailing all columns

How do you insert selected rows from table_source to table_target using SQL in MySQL where:
Both tables have the same schema
All columns should transfer except for the auto-increment id
Without explicitly writing all the column names, as that would be tedious
The trivial INSERT INTO table_target SELECT * FROM table_source fails on duplicate entries for primary key.
Either you list all of the fields you want in the insert...select, or you use something else externally to build the list for you.
SQL does not have something like SELECT * except somefield FROM, so you'll have to bite the bullet and write out the field names.
Column names have to be specified -
INSERT INTO table_target SELECT NULL, column_name1, column_name2, column_name3, ...
FROM table_source;
Just pass NULL as a value for the auto-increment id field.
Of course, primary key must be unique. It depends on what you want to achieve, but you could exclude rows with a primary key that already exists.
INSERT INTO table_target SELECT * FROM table_source
WHERE table_source.id NOT IN (SELECT id FROM table_target)
UPDATE: since you also need the extra rows, you should resolve the conflict first, does table_source have relationships? If not you could change those keys:
UPDATE table_source SET id = id + 1000
WHERE id IN (SELECT id FROM table_target)
Where 1000, is a constant, big enough so they go after the end of your table.
Tedious but safe and correct.
Writing INSERT statements without providing a list of columns leads to code that's hard to debug and, more importantly, very fragile code that will break if the definition of the table is changed.
If you absolutely can't write the column names out yourself then it's relatively easy to build a tool into your code that will create the comma-separated list for you.
This is my final solution to mass update with 'replace insert' command.
SET ##session.group_concat_max_len = ##global.max_allowed_packet;
SET #schema_db = 'db';
SET #tabl = 'table';
SET #cols = (SELECT CONCAT('`',GROUP_CONCAT(COLUMN_NAME SEPARATOR '`, `'), '`') FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = #schema_db AND TABLE_NAME = #tabl GROUP BY TABLE_NAME);
SET #Querystr = CONCAT('REPLACE INTO ',#schema_db,'.',#tabl,' SELECT ', #cols,' FROM import.tbl_', #tabl);
PREPARE stmt FROM #Querystr;
EXECUTE stmt;
I think you could use syntax like:
INSERT INTO table (a,b,c) VALUES (1,2,3)
ON DUPLICATE KEY UPDATE c=c+1;
REF: http://dev.mysql.com/doc/refman/5.0/en/insert-on-duplicate.html
Hope it helps
INSERT IGNORE just "bypass" the duplicate rows.
http://dev.mysql.com/doc/refman/5.5/en/insert.html
You can probably do it with prepared statements.
PREPARE table_target_insert FROM 'INSERT INTO table_target SELECT ? FROM table_source';
SET #cols:='';
SELECT #cols:=GROUP_CONCAT(IF(column_name = 'id','NULL',column_name) separator ",") FROM information_schema.columns WHERE table_name='table_source';
EXECUTE table_target_insert USING #cols;
It seems as if columns can not be given as a place holder in a MySQL Prepared Statement. I have compiled the following solution for testing:
SET #schema_db = 'DB';
SET #table = 'table';
SET #cols = (SELECT CONCAT(GROUP_CONCAT(COLUMN_NAME SEPARATOR ', '), "\n") FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = #schema_db AND TABLE_NAME = #table GROUP BY TABLE_NAME);
SET #Querystr = CONCAT('SELECT',' ', #cols,' ','FROM',' ',#schema_db,'.',#table,' ', 'Limit 5');
PREPARE stmt FROM #Querystr;
EXECUTE stmt;
You can use dynamic query:
DECLARE #Columns VARCHAR(MAX)=''
DECLARE #Query VARCHAR(MAX)=''
SELECT
#Columns = ISNULL(#Columns +',', '') + T.COLUMN_NAME
FROM
(
select name as COLUMN_NAME from sys.all_columns
where object_id = (select object_id from sys.tables where name = 'Source_Table')
and is_identity = 0
)T
set #Query = 'insert into Target_Table (' + SUBSTRING(#Columns,2 , 9999) + ') select ' + SUBSTRING(#Columns,2 , 9999) + ' from Source_Table';
PRINT #Query
EXEC(#Query)
The easiest way to do it is to use phpmyadmin to write the list of columns, then to change it as needed, in the example below I want to duplicate row with id=1078 and in this table I have id unique auto increment and alias unique.therefore I created my query as follow, with id & alias replaced by a desired value. and it worked like a charm.
INSERT INTO sy3_menuselect 1079, menutype, title, "alias", note, path, link, type, published, parent_id, level, component_id, checked_out, checked_out_time, browserNav, access, img, template_style_id, params, lft, rgt, home, language, client_id from sy3_menuwhere id=1078
Alternatively, to auto increment id, use the following Join statement:
INSERT INTO sy3_menuselect *
from (SELECT MAX(id+1 )from sy3_menu)a
join (select menutype, title, "alias", note, path, link, type, published, parent_id, level, component_id, checked_out, checked_out_time, browserNav, access, img, template_style_id, params, lft, rgt, home, language, client_idfrom sy3_menuwhere id=1079)b