SQL Comparing a table attribute from values from other table - sql

I want to compare values from the first table InputStrings with values in the second table StringConstraints in Sql.
InputStrings
+-----------+------------+-----------+
| Name | Address | City |
+-----------+------------+-----------+
| abcabcabc | xyxyxyxy | qweqweqwe |
| abbcabc | xyxxyxy | qweqwe |
| abccabc | xyxyxyxyxy | qwweqwe |
+-----------+------------+-----------+
StringConstraints
+---------+-----------+-----------+
| colName | minlength | maxlength |
+---------+-----------+-----------+
| Name | 2 | 20 |
| Address | 4 | 10 |
| City | 5 | 10 |
+---------+-----------+-----------+
I want to check if the length of the values in the Name column is between 2 and 20; length of values in the Address column is between 4 and 10; and length of values in the City column is between 5 and 10.
There are 68 rows like this in my table. InputString has 40 columns in it. I can't write for each and every row.
Can anyone help me make a generalized solution to compare the values?
I'm new to the database area.

this will return bad records:
Select *
from InputStrings
where (len(Name) not between (select minlength from StringContraints where colName = 'Name')
and
(select maxlength from StringContraints where colName = 'Name'))
or
(len(Address) not between (select minlength from StringContraints where colName = 'Address')
and
(select maxlength from StringContraints where colName = 'Address'))
or
(len(City) not between (select minlength from StringContraints where colName = 'City')
and
(select maxlength from StringContraints where colName = 'City'))

This is a way to create the same thing dynamically. Please keep in mind that Stack Overflow is not a coding service.
declare #sql varchar(max) =''
,#Name varchar(50)
,#min int
,#max int
,#counter int =1;
declare csr cursor
for
select colName, minlength, [maxlength] from (values ('Name',2,20),('Address',4,10),('City',5,10)) a(colName,minlength,[maxlength])
open csr
fetch next from csr
into #Name,#min,#max
set #sql = 'select * from inputstrings where '
while ##FETCH_STATUS = 0
begin
if(#counter =1 ) set #sql = #sql + '(len('+ #name+') not between ' + cast(#min as varchar(5)) + ' and ' + cast(#max as varchar(5)) + ') '
else set #sql = #sql + 'or (len('+ #name+') not between ' + cast(#min as varchar(5)) + ' and ' + cast(#max as varchar(5)) + ') '
set #counter=#counter +1
fetch next from csr
into #Name,#min,#max
end
close csr
deallocate csr
print #sql
exec(#sql)

You didn't state your DMBS, so this is a solution for Postgres:
select *
from (
select i.id,
t.*,
c.minlength,
c.maxlength,
length(t.value) between c.minlength and c.maxlength as is_valid
from inputstrings i
cross join lateral jsonb_each_text(to_jsonb(i) - 'id') as t(colname, value)
join stringconstraints c on lower(c.colname) = lower(t.colname)
) t
where not is_valid
order by id;
This first turns each row from the table inputstrings into key/value pairs and the result of that is joined to the stringconstraints table. From there it's easy to validate the column values based on the constraints. This is independent of the number of columns in inputstrings. The result will be one row per column value that violates the constraints.
For the following setup:
create table inputstrings (id integer, name text, address text, city text);
insert into inputstrings
values
(1, 'Name OK','Some Address that is too long','City Name OK'),
(2, 'N', 'Address OK', 'Cty'),
(3, 'Good Name', 'Good Address', 'Good City');
create table stringconstraints (colname text, minlength int, maxlength int);
insert into stringconstraints
values
('Name', 2, 20),
('Address', 4, 12),
('City', 5, 15);
The query returns this result:
id | colname | value | minlength | maxlength | is_valid
---+---------+-------------------------------+-----------+-----------+---------
1 | address | Some Address that is too long | 4 | 12 | false
2 | name | N | 2 | 20 | false
2 | city | Cty | 5 | 15 | false
I added the id column so that it is possible to match a invalid column value to the actual source row.
Online example: http://rextester.com/VVG55773
Second example with more columns: http://rextester.com/QCKG53573 (note the query hasn't changed)

Related

Moving result from 1:n query to repeating columns

I would like to achieve the following from a result of a 1:n join using T-sql
Surname | Givename |..Address | City
Name1....| Givename1.|..Addr11...| City11
Name1....| Givename1.|..Addr12...| City12
Name2....| Givename2.|..Addr21...| City21
Name2....| Givename2.|..Addr22...| City22
Name2....| Givename2.|..Addr23...| City23
TO:
Surname | Givename.. | Address | City... | Address | City... | Address | City
Name1....| Givename1...| Addr11....| City11. | Addr12....| City12. |
Name2....| Givename2...| Addr21....| City21. | Addr22....| City22. | Addr23....| City23
I not care about repeating columnames. Up if there is a soultion with numbers in the repeating columns it would be fine too.
Thanks
In my opinion Pivot is not a solution in this case. Because the column name should repat, and in pivot, cell values are moved to column names, also is unlike pivot no aggregate function involved.
In my thought, the following query will handle your issue. However the SQL Server has column number limit for tables.
Columns per table 1,024 Tables that include sparse column sets
include up to 30,000 columns. See sparse column sets.
You should take this considiration for your data.
DROP TABLE IF EXISTS #Test
DROP TABLE IF EXISTS ##PivotUnlimited
CREATE TABLE #Test(Surname VARCHAR(100) , GivenName VARCHAR(200),
Adress VARCHAR(100),City VARCHAR(100))
INSERT INTO #Test
VALUES
('Name1','Givename1','Addr11','City11'),
('Name1','Givename1','Addr12','City12'),
('Name2','Givename2','Addr21','City21'),
('Name2','Givename2','Addr22','City21'),
('Name2','Givename2','Addr23','City23')
,('Name5','Givename5','Addr51','City51'),
('Name5','Givename5','Addr52','City52'),
('Name5','Givename5','Addr53','City53'),
('Name5','Givename5','Addr54','City54'),
('Name3','Givename3','Addr31','City31')
DECLARE #Counter AS INT=1
DECLARE #Max AS INT
DECLARE #SQL AS VARCHAR(MAX)
SELECT #Max= MAX(DetMax) FROM
(
SELECT ROW_NUMBER() OVER(Partition by Surname ORDER BY Surname ) AS DetMax FROM #Test
) AS TMP
DROP TABLE IF EXISTS ##PivotUnlimited
CREATE TABLE ##PivotUnlimited (Surname VARCHAR(100),GivenName VARCHAR(100))
WHILE #Counter <=#Max
BEGIN
SET #SQL= 'ALTER TABLE ##PivotUnlimited ADD ADDR' + CONVERT(VARCHAR,#Counter) + ' VARCHAR(100)'
EXEC(#SQL)
SET #SQL= 'ALTER TABLE ##PivotUnlimited ADD City' + CONVERT(VARCHAR,#Counter) + ' VARCHAR(100)'
EXEC(#SQL)
SET #Counter=#Counter+1
END
INSERT INTO ##PivotUnlimited (Surname,GivenName)
SELECT DISTINCT Surname , GivenName FROM #Test
DECLARE #Name AS VARCHAR(100)
DECLARE cursorT CURSOR
FOR
SELECT DISTINCT Surname from #test
OPEN cursorT
FETCH NEXT FROM cursorT INTO #Name
WHILE ##FETCH_STATUS = 0
BEGIN
DECLARE #CounterCursor AS INT=1
DECLARE #MaxCursort AS INT =0
DECLARE #UpdateSQL AS VARCHAR(MAX)
DECLARE #UptAdr AS VARCHAR(100)
DECLARE #UptCity AS VARCHAR(100)
SELECT #MaxCursort=RowNumber FROM (
SELECT ROW_NUMBER() OVER(Partition by Surname ORDER BY Surname ) AS RowNumber FROM #Test
WHERE Surname=#Name
) AS TMP_TBL
WHILE #CounterCursor<= #MaxCursort
BEGIN
SELECT #UptAdr=Adress ,#UptCity=City FROM (
SELECT ROW_NUMBER() OVER(Partition by Surname ORDER BY Surname ) AS RowNumber,* FROM #Test
) AS TMP_TBL WHERE RowNumber=#CounterCursor and Surname=#Name
SET #UpdateSQL= 'UPDATE ##PivotUnlimited SET ADDR' + CONVERT(VARCHAR,#CounterCursor) + ' = ' + '''' + #UptAdr +'''' + ' , '
+ ' City' + CONVERT(VARCHAR,#CounterCursor) + ' = ' + '''' + #UptCity +'''' + ' WHERE Surname = ' + '''' + #Name + ''''
EXEC (#UpdateSQL)
SET #CounterCursor=#CounterCursor+1
END
FETCH NEXT FROM cursorT INTO #Name
END
CLOSE cursorT
DEALLOCATE cursorT
SELECT * FROM ##PivotUnlimited
+---------+-----------+--------+--------+--------+--------+--------+--------+--------+--------+
| Surname | GivenName | ADDR1 | City1 | ADDR2 | City2 | ADDR3 | City3 | ADDR4 | City4 |
+---------+-----------+--------+--------+--------+--------+--------+--------+--------+--------+
| Name1 | Givename1 | Addr11 | City11 | Addr12 | City12 | NULL | NULL | NULL | NULL |
| Name2 | Givename2 | Addr21 | City21 | Addr22 | City21 | Addr23 | City23 | NULL | NULL |
| Name3 | Givename3 | Addr31 | City31 | NULL | NULL | NULL | NULL | NULL | NULL |
| Name5 | Givename5 | Addr51 | City51 | Addr52 | City52 | Addr53 | City53 | Addr54 | City54 |
+---------+-----------+--------+--------+--------+--------+--------+--------+--------+--------+

Splitting dynamically SQL columns into multiple columns based on a different column value

I am trying to convert dynamically a table like this:
+----+---------+-------+
| ID | Subject | Users |
+----+---------+-------+
| 1 | Hi! | Anna |
| 2 | Hi! | Peter |
| 3 | Try | Jan |
| 4 | Try | Peter |
| 5 | Try | Jan |
| 6 | Problem | Anna |
| 7 | Problem | José |
| 8 | Test | John |
| 9 | Test | John |
| 10 | Hi! | Anna |
| 11 | Hi! | José |
| 12 | Hi! | Anna |
| 13 | Hi! | Joe |
+----+---------+-------+
Into something like that:
+----+---------+-------+-------+-------+-------+
| ID | Subject | User1 | User2 | User3 | User4 |
+----+---------+-------+-------+-------+-------+
| 1 | Hi! | Anna | Peter | José | NULL |
| 2 | Try | Jan | Peter | NULL | NULL |
| 3 | Problem | Anna | José | NULL | NULL |
| 4 | Test | John | NULL | NULL | NULL |
+----+---------+-------+-------+-------+-------+
I have been reading the following links, but they are thought for splitting a column into a predefined number of columns:
Splitting SQL Columns into Multiple Columns Based on Specific Column Value
Split column into two columns based on type code in third column
I would need to split it dinamically depending on the content of the table.
SQL:
--【Build Test Data】
create table #Tem_Table ([ID] int,[Subject] nvarchar(20),[Users] nvarchar(20));
insert into #Tem_Table ([ID],[Subject] ,[Users]) values
('1','Hi!','Anna')
,('2','Hi!','Peter')
,('3','Try','Jan')
,('4','Try','Peter')
,('5','Try','Jan')
,('6','Problem','Anna')
,('7','Problem','José')
,('7','Test','John')
,('9','Test','John')
,('10','Hi! ','Anna')
,('11','Hi! ','José')
,('12','Hi! ','Anna')
,('13','Hi! ','Joe')
;
--STEP 1 distinct and ROW_NUMBER
with distinct_table as (
select [Subject],[Users]
,ROW_NUMBER() OVER (PARTITION BY [Subject] order by [Users]) [rank]
from (
select distinct [Subject],[Users] from #Tem_Table
) T00
)
--STEP 2 Group by row_count
,group_table as (
select [Subject]
from distinct_table T
group by [Subject]
)
--STEP 3 Use Left Join and Rank
select
T.[Subject],T1.[Users] as User1, T2.[Users] as User2 , T3.[Users] as User3, T4.[Users] as User4
from group_table T
left join distinct_table T1 on T.[Subject] = T1.[Subject] and T1.[rank] = 1
left join distinct_table T2 on T.[Subject] = T2.[Subject] and T2.[rank] = 2
left join distinct_table T3 on T.[Subject] = T3.[Subject] and T3.[rank] = 3
left join distinct_table T4 on T.[Subject] = T4.[Subject] and T4.[rank] = 4
order by [Subject];
result:
-------------------- -------------------- -------------------- -------------------- --------------------
Hi! Anna Joe José Peter
Problem Anna José NULL NULL
Test John NULL NULL NULL
Try Jan Peter NULL NULL
Update the Dynamic version :
--STEP 1 distinct and ROW_NUMBER
SELECT * into #distinct_table from (
select [Subject],[Users]
,ROW_NUMBER() OVER (PARTITION BY [Subject] order by [Users]) [rank]
from (
select distinct [Subject],[Users] from #Tem_Table
) T00
)T;
--STEP 2 Group by row_count
SELECT * into #group_table from (
select [Subject] ,count(1) [count]
from #distinct_table T
group by [Subject]
)T;
--Use Exec
DECLARE #select_sql AS NVARCHAR(MAX) = ' select T.[Subject] ',
#join_sql AS NVARCHAR(MAX) = ' from #group_table T ',
#max_count INT = (SELECT max([count]) FROM #group_table),
#temp_string NVARCHAR(5),
#temp_string_addone NVARCHAR(5)
;
DECLARE #index int = 0 ;
WHILE #index < #max_count
BEGIN
sELECT #temp_string = Convert(nvarchar(10),#index);
sELECT #temp_string_addone = Convert(nvarchar(10),#index+1);
select #select_sql = #select_sql + ' , T'+#temp_string_addone+'.[Users] as User'+#temp_string_addone+' '
select #join_sql = #join_sql + 'left join #distinct_table T'+#temp_string_addone+' on T.[Subject] = T'+#temp_string_addone+'.[Subject] and T'+#temp_string_addone+'.[rank] = '+#temp_string_addone+' ';
SET #index = #index + 1;
END;
EXEC (#select_sql
+ #join_sql
+' order by [Subject]; ')
;
CREATE TABLE mytable
([ID] int, [Subject] varchar(7), [Users] varchar(5))
;
INSERT INTO mytable
([ID], [Subject], [Users])
VALUES
(1, 'Hi!', 'Anna'),
(2, 'Hi!', 'Peter'),
(3, 'Try', 'Jan'),
(4, 'Try', 'Peter'),
(5, 'Try', 'Jan'),
(6, 'Problem', 'Anna'),
(7, 'Problem', 'José'),
(8, 'Test', 'John'),
(9, 'Test', 'John'),
(10, 'Hi!', 'Anna'),
(11, 'Hi!', 'José'),
(12, 'Hi!', 'Anna'),
(13, 'Hi!', 'Joe')
;
select distinct subject,
(select users from (
select distinct users from mytable where subject=m.subject) a order by users offset 0 rows fetch next 1 row only) user1,
(select users from (
select distinct users from mytable where subject=m.subject) a order by users offset 1 rows fetch next 1 row only) user2,
(select users from (
select distinct users from mytable where subject=m.subject) a order by users offset 2 rows fetch next 1 row only) user3,
(select users from (
select distinct users from mytable where subject=m.subject) a order by users offset 3 rows fetch next 1 row only) user4
from mytable m
you can use below dynamic query to get the result-
create table test_Raw(ID int ,Subject varchar(100), Users varchar(100))
insert into test_Raw
values (1,' Hi!','Anna'),
(2,' Hi!','Peter'),
(3,'Try','Jan'),
(4,'Try','Peter'),
(5,'Try','Jan'),
(6,'Problem','Anna'),
(7,'Problem','José'),
(8,'Test','John'),
(9,'Test','John'),
(10,' Hi!','Anna'),
(11,' Hi!','José'),
(12,' Hi!','Anna'),
(13,' Hi!','Joe')
--select * from test_Raw
select dense_RANK() over( order by Subject) Ranking1, dense_RANK() over(partition by Subject order by users) Ranking2 , Subject , Users
into test
from test_Raw
group by Subject , Users
order by 3
declare #min int , #mx int , #Select nvarchar(max) , #from nvarchar(max) , #vmin varchar(3)
select #min= 1 , #mx = MAX(Ranking2) , #Select= 'select ' , #from = ' from test t1 ' , #vmin = '' from test
while (#min<=#mx)
begin
select #vmin = CAST(#min as varchar(3))
select #Select = #Select + CASE WHEN #min = 1 THEN 't1.Ranking1 as ID , t1.Subject , t1.Users AS User1 ' ELSE ',t' +#vmin+'.Users as User'+#vmin END
select #from = #from + CASE WHEN #min = 1 THEN '' ELSE ' left join test t'+#vmin + ' on t1.Ranking1 = t' + #vmin + '.Ranking1 and t1.Ranking2 + ' + cast (#min-1 as varchar(10)) + ' = t'+#vmin+'.Ranking2' END
set #min = #min + 1
end
select #Select = #Select + #from + ' where t1.Ranking2 = 1'
exec sp_executesql #Select

SQL SELECT: concatenated column with line breaks and heading per group

I have the following SQL result from a SELECT query:
ID | category| value | desc
1 | A | 10 | text1
2 | A | 11 | text11
3 | B | 20 | text20
4 | B | 21 | text21
5 | C | 30 | text30
This result is stored in a temporary table named #temptab. This temporary table is then used in another SELECT to build up a new colum via string concatenation (don't ask me about the detailed rationale behind this. This is code I took from a colleague). Via FOR XML PATH() the output of this column is a list of the results and is then used to send mails to customers.
The second SELECT looks as follows:
SELECT t1.column,
t2.column,
(SELECT t.category + ' | ' + t.value + ' | ' + t.desc + CHAR(9) + CHAR(13) + CHAR(10)
FROM #temptab t
WHERE t.ID = ttab.ID
FOR XML PATH(''),TYPE).value('.','NVARCHAR(MAX)') AS colname
FROM table1 t1
...
INNER JOIN #temptab ttab on ttab.ID = someOtherTable.ID
...
Without wanting to go into too much detail, the column colname becomes populated with several entries (due to multiple matches) and hence, a longer string is stored in this column (CHAR(9) + CHAR(13) + CHAR(10) is essentially a line break). The result/content of colname looks like this (it is used to send mails to customers):
A | 10 | text1
A | 11 | text11
B | 20 | text20
B | 21 | text21
C | 30 | text30
Now I would like to know, if there is a way to more nicely format this output string. The best case would be to group the same categories together and add a heading and empty line between different categories:
*A*
A | 10 | text1
A | 11 | text11
*B*
B | 20 | text20
B | 21 | text21
*C*
C | 30 | text30
My question is: How do I have to modify the above query (especially the string-concatenation-part) to achieve above formatting? I was thinking about using a GROUP BY statement, but this obviously does not yield the desired result.
Edit: I use Microsoft SQL Server 2008 R2 (SP2) - 10.50.4270.0 (X64)
Declare #YourTable table (ID int,category varchar(50),value int, [desc] varchar(50))
Insert Into #YourTable values
(1,'A',10,'text1'),
(2,'A',11,'text11'),
(3,'B',20,'text20'),
(4,'B',21,'text21'),
(5,'C',30,'text30')
Declare #String varchar(max) = ''
Select #String = #String + Case when RowNr=1 Then Replicate(char(13)+char(10),2) +'*'+Category+'*' Else '' end
+ char(13)+char(10) + category + ' | ' + cast(value as varchar(25)) + ' | ' + [desc]
From (
Select *
,RowNr=Row_Number() over (Partition By Category Order By Value)
From #YourTable
) A Order By Category, Value
Select Substring(#String,5,Len(#String))
Returns
*A*
A | 10 | text1
A | 11 | text11
*B*
B | 20 | text20
B | 21 | text21
*C*
C | 30 | text30
This should return what you want
Declare #YourTable table (ID int,category varchar(50),value int, [desc] varchar(50))
Insert Into #YourTable values
(1,'A',10,'text1'),
(2,'A',11,'text11'),
(3,'B',20,'text20'),
(4,'B',21,'text21'),
(5,'C',30,'text30');
WITH Categories AS
(
SELECT category
,'**' + category + '**' AS CatCaption
,ROW_NUMBER() OVER(ORDER BY category) AS CatRank
FROM #YourTable
GROUP BY category
)
,Grouped AS
(
SELECT c.CatRank
,0 AS ValRank
,c.CatCaption AS category
,-1 AS ID
,'' AS Value
,'' AS [desc]
FROM Categories AS c
UNION ALL
SELECT c.CatRank
,ROW_NUMBER() OVER(PARTITION BY t.category ORDER BY t.Value)
,t.category
,t.ID
,CAST(t.value AS VARCHAR(100))
,t.[desc]
FROM #YourTable AS t
INNER JOIN Categories AS c ON t.category=c.category
)
SELECT category,Value,[desc]
FROM Grouped
ORDER BY CatRank,ValRank
The result
category Value desc
**A**
A 10 text1
A 11 text11
**B**
B 20 text20
B 21 text21
**C**
C 30 text30

How to prepend column names into column values?

Having the following table:
| Some Table |
| Id | Name | Age |
| 23 | Marc | 41 |
| 54 | Edu | 34 |
I want to get:
|Another Table's Column| Id | Name | Age |
| ..... | Id#23 | Name#Marc | Age#41 |
| ..... | Id#54 | Name#Edu | Age#34 |
This query will be used inside a dynamic sql, the name of the table is going to have passed as a parameter.
The final query must show data of at least two tables, and only one of them must show data with his column names as a prefix.
Not sure I understand what you want, but here is the script to show column names within the result for any passed table:
DECLARE #t NVARCHAR(128) = '[Person].[Person]';
DECLARE #l NVARCHAR(2000) = '';
DECLARE #s NVARCHAR(4000) = '';
SELECT #l = (
SELECT ' ''#' + Name + ''' + CAST([' + Name + '] as VARCHAR(max)) as [' + Name + '],'
FROM sys.columns
WHERE object_id = OBJECT_ID(#t)
ORDER BY column_id
FOR XML PATH(''));
SELECT #s = 'SELECT ' + LEFT(#l,LEN(#l)-1) + ' FROM ' + #t + ';'
PRINT #s
EXEC (#s)
You can tune it to link another table or many tables

SQL Column Names from a Excel Sheet

Im using SSMS 2014 and SQL Server 2014. I need to change the column names at the end of a query result by using a excel file or table with the data.
After some SELECT statements and stuff i get a table with data for example
+---------+---------+------+
| Col1 | Col2 | Col3 |
+---------+---------+------+
| Value 1 | Value 2 | 123 |
| Value 2 | Value 2 | 456 |
| Value 3 | Value 3 | 789 |
+---------+---------+------+
And the table or excelfile
+----+---------+-----------+-----------+
| ID | ColName | Language | Addition |
+----+---------+-----------+-----------+
| 1 | Col1 | D | 123 |
| 2 | Col2 | D | 456 |
| 3 | Col3 | D | 789 |
| 4 | Col1 | E | 123 |
| 5 | Col2 | E | 456 |
| 6 | Col3 | E | 789 |
+----+---------+-----------+-----------+
What i try to do is to get the addition value of each column and add it to the column name. It should only add the values with the specific language. #setLang = 'D'
Col1 + Addition
Col2 + Addition
Col3 + Addition
+-------------+-------------+---------+
| Col1 123 | Col2 456 | Col3789 |
+-------------+-------------+---------+
| Value 1 | Value 2 | 123 |
| Value 2 | Value 2 | 456 |
| Value 3 | Value 3 | 789 |
+-------------+-------------+---------+
I tried it over Information_Schema.Columns and filter with where table = 'resultTable' and Column_name = #cName. Maybe i need a loop to get each columnname.
Thanks for reading and trying to help me.
Give this a go - it uses a table, not an excel file (but that seems to be an option in your question). I have made some temporary tables and filled them with your values, but you will obviously not need to do this. You will need to replace out the references to the tempdb with the name of the database where your tables are kept and the temp tables #Original and #ExcelInfo with your table names.
I have also used a temp table to add an 'Id IDENTITY(1,1)` Column to the table holding your original data. This is needed to keep the unpivot in check; if you can modify your table to include an Id, that will make things easier, but if not, you can insert into a temp table as I have done.
The script is shorter than it looks - the whole first bit is just setting up the example; the real answer starts at the line that declares your language variable.
/*
The script between the first two dividing lines of dashes is just used to set up the example. The bit you want is from
the "-- Test Variables --" line.
*/
-----------------------------------------------------------------------------------------------------------------------
IF OBJECT_ID('tempdb..#Original') IS NOT NULL DROP TABLE #Original
IF OBJECT_ID('tempdb..#ExcelInfo') IS NOT NULL DROP TABLE #ExcelInfo
CREATE TABLE #Original
( Col1 VARCHAR(50)
,Col2 VARCHAR(50)
,Col3 VARCHAR(50))
CREATE TABLE #ExcelInfo
( Id INT IDENTITY(1,1) NOT NULL
,ColName VARCHAR(50) NOT NULL
,[Language] CHAR(1) NOT NULL
,Addition INT NOT NULL)
INSERT #Original
SELECT *
FROM
( SELECT 'Value 1' AS Col1,'Value 2' AS Col2 ,123 AS Col3
UNION SELECT 'Value 2' ,'Value 2' ,456
UNION SELECT 'Value 3' ,'Value 3' ,789) AS This
ORDER BY Col1
INSERT #ExcelInfo (ColName,[Language],Addition)
SELECT *
FROM
( SELECT 'Col1' AS ColName, 'D' AS [Language], 123 AS Addition
UNION SELECT 'Col2','D',456
UNION SELECT 'Col3','D',789
UNION SELECT 'Col1','E',123
UNION SELECT 'Col2','E',456
UNION SELECT 'Col3','E',789) AS This
ORDER BY [Language], Addition
-----------------------------------------------------------------------------------------------------------------------
-- Test Variables --
DECLARE #SetLang CHAR(1) = 'D'
-----------------------------------------------------------------------------------------------------------------------
-- make the default empty, not null on our dynamic string, so it can be added to
DECLARE #Columns VARCHAR(MAX) = ''
DECLARE #SQL VARCHAR(MAX)
CREATE TABLE #OriginalColumns
( Id INT IDENTITY(1,1)
,Name VARCHAR(50))
CREATE TABLE #BasicResult
(Id INT NOT NULL, Name VARCHAR(50), Value VARCHAR(50))
-- If you can add an id column to your original table, this bit is unecessary - you can use yours in place of this table
CREATE TABLE #Original_WITH_Id
( Id INT IDENTITY(1,1)
,Col1 VARCHAR(50)
,Col2 VARCHAR(50)
,Col3 VARCHAR(50))
INSERT #Original_WITH_Id
SELECT * FROM #Original
-----------------------------------------------------------------------------------------------------------------------
-- List out the columns and put the list in a variable.
INSERT #OriginalColumns
SELECT QUOTENAME(Col.name)
FROM tempdb.sys.columns AS Col
WHERE Col.object_id = OBJECT_ID('tempdb.dbo.#Original_WITH_Id')
-- we're not interested in the identity column at the moment
AND Col.name <> 'Id'
-- keep everything in the same order as they are listed on the table
ORDER BY Col.column_id
SELECT #Columns = #Columns + ',' + Name
FROM #OriginalColumns
-- clip off the leading comma
SELECT #Columns = SUBSTRING(#Columns,2,LEN(#Columns))
-- get a full list of everything, creating our new list of columns as we go, using the Id column to keep a mark on which
-- row each record originally came from
SET #SQL =
'INSERT #BasicResult
SELECT Id, New.Name, Value FROM
(SELECT Id, Name, Value
FROM #Original_WITH_Id
UNPIVOT (Value FOR Name IN (' + #Columns + ')) Unpvt) AS Old
JOIN (SELECT ColName, CONVERT(VARCHAR(50),ColName) + '' '' + CONVERT(VARCHAR(50),Addition) AS Name
FROM #ExcelInfo
WHERE [Language] = ''' + #SetLang + ''') AS New ON Old.Name = New.ColName'
PRINT #SQL
EXEC (#SQL)
-- now update our list of columns to be the new column headings
SET #Columns = ''
SELECT #Columns = #Columns + ',' + QUOTENAME(Name) FROM (SELECT DISTINCT Name FROM #BasicResult) AS Names
SELECT #Columns = SUBSTRING(#Columns,2,LEN(#Columns))
-- pivout our results back out to their original format, but with the new column headings (include the Id if you want)
SET #SQL =
'SELECT /*Id,*/ ' + #Columns + '
FROM
(SELECT Id, Name,Value
FROM #BasicResult) AS Up
PIVOT (MAX(Value) FOR Name IN (' + #Columns + ')) AS Pvt'
PRINT #SQL
EXEC (#SQL)
-- clean up --
DROP TABLE #OriginalColumns
DROP TABLE #BasicResult
Hope that helps! There may be a more efficient way to do this... I'm not sure.
Okay i tried it again but now without the Excelfile. I made a CSV out of the Excelfile and insert it with Bulk to my created Table:
IF NOT EXISTS(SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 'CSVTest')
BEGIN
CREATE TABLE _DICTIONARY
( _TableName VARCHAR (20),
_ColumnName VARCHAR (20),
_Language VARCHAR (20),
_FieldShort VARCHAR (50),
_FieldMid VARCHAR (50),
_FieldLong VARCHAR (50)
)
BULK
INSERT _DICTIONARY
FROM 'C:\_DICTIONARY.csv'
WITH
(
FIELDTERMINATOR = ';',
ROWTERMINATOR = '\n'
)
END
After that i rename all Columns by using a Cursor
DECLARE #dic_tableName as nvarchar(50),
#dic_columnName as nvarchar(50),
#db_tableName as nvarchar(50),
#db_columnName as nvarchar(50);
DECLARE C CURSOR FAST_FORWARD FOR
SELECT _TableName, _ColumnName FROM _DICTIONARY
OPEN C;
FETCH NEXT FROM C INTO #dic_tableName, #dic_columnName;
WHILE ##FETCH_STATUS = 0
BEGIN
IF EXISTS(SELECT TABLE_NAME, COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = #dic_tableName AND COLUMN_NAME = #dic_columnName)
BEGIN
SET #db_tableName = #dic_tableName + '.' + #dic_columnName
SET #db_columnName = #dic_tableName + '_' + #dic_columnName
EXEC sp_rename #db_tableName, #db_columnName ,'COLUMN'
FETCH NEXT FROM C INTO #dic_tableName, #dic_columnName;
END
ELSE
BEGIN
FETCH NEXT FROM C INTO #dic_tableName, #dic_columnName;
END
END
CLOSE C;
DEALLOCATE C;
Its doing its job.