SQL query construction issue - sql

There two tables:
Table1
field1 | field2
Table2
field1
“string1”
“string2”
I need to insert concatenation of table2.field1 values into table1, so it looks like
insert into table1(field1, field2) values (1, “string1string2”);
How can I do it? Is there any SQL-standard way to do it?
PS: string1 and string2 are values of the field1 column.
PPS: the main subtask of my question is, how can I get the result of select query into one row? All examples I've seen just use concatenation, but in all your examples SELECT subquery does not return string concatenation for all values of the table2.field1 column.

There is no ANSI standard SQL way to do this.
But in MySQL you can use GROUP_CONCAT
insert into table1 ( field1, field2 )
select 1, group_concat(field1) from table2
In SQL Server 2005 and later you can use XML PATH,
insert into table1 ( field1, field2 )
select 1, (select field1 from table2
for xml path(''), type).value('.','nvarchar(max)')
In Oracle, you can refer to Stack Overflow question How can I combine multiple rows into a comma-delimited list in Oracle?.

INSERT INTO TABLE1 (FIELD1, FILED2) VALUES (1, CONCAT("string1", "string2"))

try this :
insert into table1(field1, field2)
select table2.field1, table2.string1 || table2.string2 from table2;
You can add a where clause to the query to select only some entries from table2 :
insert into table1(field1, field2)
select table2.field1, table2.string1 || table2.string2 from table2
where table2.field = 'whatever';

I'd try with
insert table1 select field1, string1+string2 from table2
tested with MSSQL Server 2008
create table #t1 (n int, s varchar(200))
create table #t2 (n int, s1 varchar(100), s2 varchar(100))
insert #t2 values (1, 'one', 'two') -- worked without into ???
insert #t2 values (2, 'three', 'four') -- worked without into ???
insert #t1 select n, s1+s2 from #t2 -- worked without into ???
select * from #t1
drop table #t1
drop table #t2
After the edit:
No, if you have no way to identify the lines in table2 and sort them the way you want it is impossible. Remember that, in the absence of a order by in the SQL statement, lines can be returned in any order whatsoever

Assuming this is SQL server,
Insert into table1 (field1, field2)
select field1, string1 + string2
from table2
In oracle you will do it as -
Insert into table1 (field1, field2)
select field1, string1 || string2
from table2

Related

Insert multiple rows in a single query using results of a select statement

I am looking for a compact way to do this - insert multiple rows into a table with values from multiple columns of a row from another table. My destination table is really a list with a single column:
declare #stringList table
(
val nvarchar(100)
)
This is how we can insert multiple rows:
INSERT INTO #stringList ( val ) VALUES
Val1, Val2, Val3, ...
This is how we insert from a select:
INSERT INTO #stringList
SELECT col1 FROM table1 where id=something
But I cannot seem to find a way to use both at the same time.
I can select from one column:
insert into #stringList (val)
select col1 from table1 where id=something
But it doesn't extend to multiple columns:
insert into #stringList (val)
select col1, col2 from table1 where id=something
--The select list for the INSERT statement contains more items than the insert list. The number of SELECT values must match the number of INSERT columns.
I have tried various ways including using parentheses, but the syntax is not accepted:
insert into #stringList (val)
(select col1 from table1 where id=something,
select col2 from table1 where id=something
Any idea if what I want is doable?
You can unpivot using cross apply:
insert into #stringList (val)
select v.col
from table1 t1 cross apply
(values (t1.col1), (t1.col2)) v(col)
where t1.id = something;

SQL transform table with multiple columns to two tables with FK between them

I need to convert my table with several fields to two other tables where one of the new tables has a row for each field in the first table in Microsoft SQL Server.
Table1(Table1Id, Field1, Field2, Field3)
for each row in Table1 create
Table2a(Table2aId)
Table2b(Table2bId, Table2aId, Field1)
Table2b(Table2bId, Table2aId, Field2)
Table2b(Table2bId, Table2aId, Field3)
Details
I currently have the table
Table1
[dbo].[CommunityAssetTemplates]
,[CommunityId]
,[CommunityAssetTemplateId]
,[BaseHouseSpecsAssetId]
,[CommunityLogoAssetId]
,[CommunityMarketingMapAssetId]
,[CommunityPhotoAssetId]
,[CommunityVideoDraftAssetId]
,[CommunityVideoAssetId]
This was mostly a quick way to fulfill a business need before we fully implemented the new feature where users can define multiple templates with different assets in them, so I made two new tables one is just to relate the second table to a Community
Table2a
[dbo].[CommunityAssetDataTemplates]
,[CommunityAssetDataTemplateId]
,[CommunityAssetTemplateTypeId]
,[CommunityId]
Table2b
[dbo].[CommunityAssetTemplateFiles]
,[CommunityAssetTemplateFileId]
,[CommunityAssetDataTemplateId]
,[CommunityAssetId]
These two tables map together like so, each Table1 row creates 1 Table2a row and 6 Table2b rows
Table2a
[CommunityAssetDataTemplateId] Auto Increments
[CommunityAssetTemplateTypeId] = 1
[CommunityId] = Table1.CommunityId
Table2b - 1
[CommunityAssetTemplateFileId] Auto increments
,[CommunityAssetDataTemplateId] = Table2a.[CommunityAssetDataTemplateId]
,[CommunityAssetId] = Table1.[BaseHouseSpecsAssetId] (THIS CHANGES)
Table2b - 2
[CommunityAssetTemplateFileId] Auto increments
,[CommunityAssetDataTemplateId] = Table2a.[CommunityAssetDataTemplateId]
,[CommunityAssetId] = Table1.[CommunityLogoAssetId] (THIS CHANGES)
continues for the remaining 4 'AssetId's fields of Table1
Here is one way to accomplish this using CROSS APPLY to separate Field1, Field2, and Field3 columns into rows:
insert into Table2A (Table2Id)
select Table1Id from Table1
insert into Table2B(Table2Id, Field4)
select Table1Id, Field
from Table1
cross apply (values(Field1), (Field2), (Field3)) as ColumnsAsRows(Field)
Here is a sample:
declare #t1 table (Table1Id int identity(1,1), Field1 int, Field2 int, Field3 int)
declare #t2 table (Table2Id int primary key clustered)
declare #t3 table (Table3Id int identity(1,1) primary key clustered, Table2Id int, Field4 int)
insert into #t1 (Field1, Field2, Field3)
values (1, 2, 3), (4, 5, 6), (7, 8, 9)
select * from #t1
insert into #t2 (Table2Id)
select Table1Id from #t1
insert into #t3 (Table2Id, Field4)
select Table1Id, Field
from #t1
cross apply (values(Field1), (Field2), (Field3)) as ColumnsAsRows(Field)
select * from #t2
select * from #t3

SQL get multiple values of columns in one row

I am using MS Sql server 2008 R2.
I have a query that gives me output like this
Col1....Col2
CV1.....AV1
CV1.....AV2
CV2.....AV3
CV2.....AV4
The query is
select Tab1.Col1, Tab2.Col2
from Table1 Tab1
JOIN Table2 Tab2 on Tab1.PKID = Tab2.FKID
What I want is one row for each distinct values in Col1 and in Col2 all the values related to col1 with comma or pipeline delimiter
Col1....Col2
CV1.....AV1,AV2
CV2.....AV3,AV4
Can anyone help me on this?
Basically I need something like group_concat that is available in My sql
CREATE TABLE a(
Col1 varchar(50),
Col2 varchar(20));
INSERT INTO a (Col1,Col2) values ('CV1','AV1');
INSERT INTO a (Col1,Col2) values ('CV1','AV2');
INSERT INTO a (Col1,Col2) values ('CV2','AV3');
INSERT INTO a (Col1,Col2) values ('CV2','AV4');
with t as (SELECT Col1,(CAST(Col2 AS nvarchar (12))) as col2 from a )
Select distinct T2.Col1,
substring((Select ',' + T1.col2 AS [text()]
From t T1
Where T1.Col1 = T2.Col1
ORDER BY T1.Col1
For XML PATH ('')),2, 100) [col2]
From t T2
Try this query. I am doing it in sql server. check at sqlfidddle
http://sqlfiddle.com/#!3/7ab28/1

SQL : Retrieve inserted row IDs array / table

i have the following statement:
INSERT INTO table1 (field1, FIELD2)
SELECT f1, f2 FROM table2 -- returns 20 rows
after insert i need to know the array/table of IDs generated in table1.ID which is INT IDENTITY
thanx in advance.
Use the OUTPUT clause (SQL2005 and up):
DECLARE #IDs TABLE(ID int)
INSERT INTO table1(Field1, Field2)
OUTPUT inserted.ID into #IDs(ID)
SELECT Field1, Field2 FROM table2
If you want to know exactly which rows from table2 generated which ID in table1 (and Field1 and Field2 aren't enough to identify that), you'll need to use MERGE:
DECLARE #IDs TABLE(Table1ID int, Table2ID int)
MERGE table1 AS T
USING table2 AS S
ON 1=0
WHEN NOT MATCHED THEN
INSERT (Field1, Field2) VALUES(S.Field1, S.Field2)
OUTPUT inserted.ID, S.ID INTO #IDs(Table1ID, Table2ID)
Use SCOPE_IDENTITY()
SELECT SCOPE_IDENTITY()
http://msdn.microsoft.com/en-us/library/ms190315(v=sql.105).aspx

Remove duplicate from a table

The database type is PostGres 8.3.
If I wrote:
SELECT field1, field2, field3, count(*)
FROM table1
GROUP BY field1, field2, field3 having count(*) > 1;
I have some rows that have a count over 1. How can I take out the duplicate (I do still want 1 row for each of them instead of +1 row... I do not want to delete them all.)
Example:
1-2-3
1-2-3
1-2-3
2-3-4
4-5-6
Should become :
1-2-3
2-3-4
4-5-6
The only answer I found is there but I am wondering if I could do it without hash column.
Warning
I do not have a PK with an unique number so I can't use the technique of min(...). The PK is the 3 fields.
This is one of many reasons that all tables should have a primary key (not necessarily an ID number or IDENTITY, but a combination of one or more columns that uniquely identifies a row and which has its uniqueness enforced in the database).
Your best bet is something like this:
SELECT field1, field2, field3, count(*)
INTO temp_table1
FROM table1
GROUP BY field1, field2, field3 having count(*) > 1
DELETE T1
FROM table1 T1
INNER JOIN (SELECT field1, field2, field3
FROM table1
GROUP BY field1, field2, field3 having count(*) > 1) SQ ON
SQ.field1 = T1.field1 AND
SQ.field2 = T1.field2 AND
SQ.field3 = T1.field3
INSERT INTO table1 (field1, field2, field3)
SELECT field1, field2, field3
FROM temp_table1
DROP TABLE temp_table1
One possible answer is:
CREATE <temporary table> (<correct structure for table being cleaned>);
BEGIN WORK; -- if needed
INSERT INTO <temporary table> SELECT DISTINCT * FROM <source table>;
DELETE FROM <source table>
INSERT INTO <source table> SELECT * FROM <temporary table>;
COMMIT WORK; -- needed
DROP <temporary table>;
I'm not sure whether the 'work' is needed on transaction statements, nor whether the explicit BEGIN is necessary in PostgreSQL. But the concept applies to any DBMS.
The only thing to beware of is referential constraints and in particular triggered delete operations. If those exist, this may prove less satisfactory.
This will use the OID Object ID (if the table was created with it):
DELETE FROM table1
WHERE OID NOT IN (SELECT MIN (OID)
FROM table1
GROUP BY field1, field2, field3)
Well I should misunderstand something but I'll say :
SELECT DISTINCT field1, field2, field3 FROM table1
Too easy to be good? ^^
This is the simplest method I've found:
Postgre SQL syntax:
CREATE TABLE tmp AS SELECT distinct * FROM table1
truncate table table1
insert into table1 select * from tmp
drop table tmp
T-SQL syntax:
select distinct * into #tmp from table1
truncate table table1
insert into table1 select * from #tmp
drop table #tmp
A good Answer for this problem, but for SQL Server. It uses the ROWCOUNT that SQL Server offers, to good effect. I have never used PostgreSQL and hence don't know the equivalent of ROWCOUNT in PostgreSQL.
Using TSQL, no idea if Postgres supports temp tables but you could select into a temp table, and then loop through and delete and insert your results back into the original
-- **Disclaimer** using TSQL
-- You could select your records into a temp table with a pk
Create Table #dupes
([id] int not null identity(1,1), f1 int, f2 int, f3 int)
Insert Into #dupes (f1,f2,f3) values (1,2,3)
Insert Into #dupes (f1,f2,f3) values (1,2,3)
Insert Into #dupes (f1,f2,f3) values (1,2,3)
Insert Into #dupes (f1,f2,f3) values (2,3,4)
Insert Into #dupes (f1,f2,f3) values (4,5,6)
Insert Into #dupes (f1,f2,f3) values (4,5,6)
Insert Into #dupes (f1,f2,f3) values (4,5,6)
Insert Into #dupes (f1,f2,f3) values (7,8,9)
Select f1,f2,f3 From #dupes
Declare #rowCount int
Declare #counter int
Set #counter = 1
Set #rowCount = (Select Count([id]) from #dupes)
while (#counter < #rowCount + 1)
Begin
Delete From #dupes
Where [Id] <>
(Select [id] From #dupes where [id]=#counter)
and
(
[f1] = (Select [f1] from #dupes where [id]=#counter)
and
[f2] = (Select [f2] from #dupes where [id]=#counter)
and
[f3] = (Select [f3] from #dupes where [id]=#counter)
)
Set #counter = #counter + 1
End
Select f1,f2,f3 From #dupes -- You could take these results and pump them back into --your original table
Drop Table #dupes
Tested this on MS SQL Server 2000. Not familiar with Postgres' options but maybe this will lead you in a right direction.