Get Dataset as Header for Another Table - sql

I get the columns and the data of all surveys I have in the online database through my API an separately.
The first example are the column headers of the first two surveys
Column Table
ID Col1 Col2 Col3
------------------------------------
0 Name Birhtdate Country
1 Time Name Address
The data I get for the first survey is like
Data Table
ID Col1 Col2 Col3
------------------------------------
0 James 11-11-2011 Japan
1 Tobi 26-02-2014 India
Now I want to merge the data and the columns so that the column names are the header of the final table like
Final Table
ID Name Birthday Country
------------------------------------
0 James 11-11-20111 Japan
1 Tobi 26-02-2014 India
All the attemps I have made yet with Select statements gave me
Wrong Result Table
ID Col1 Col2 Col3
------------------------------------
0 Name Birthdate Country
1 James 11-11-20111 Japan
2 Tobi 26-02-2014 India
Could anyone help me get the final table (view, temp Table... whatever) out of my data? I am working with SQL-Server 2016

You can use dynamic SQL to define column alias names coming from another table:
declare #col1 varchar(50), #col2 varchar(50), #col3 varchar(50)
declare #sql nvarchar(max)
create table #t1 (ID int, Col1 varchar(50), Col2 varchar(50), Col3 varchar(50))
insert into #t1 values
(0, 'Name', 'Birhtdate', 'Country')
,(1, 'Time', 'Name' , 'Address')
create table #t2 (ID int, Col1 varchar(50), Col2 varchar(50), Col3 varchar(50))
insert into #t2 values
(0, 'James','2011-11-11', 'Japan')
, (1, 'Tobi' ,'2014-02-26', 'India')
select #col1=col1, #col2=col2, #col3=col3 from #t1 where id = 0
set #sql=concat('select id, col1 as ', #col1, ', col2 as ',
#col2, ', col3 as ', #col3, ' from #t2')
exec (#sql)
Result:

The only way to achieve such a result using pure T-SQL is to use dynamic SQL.
You can do something like this:
DECLARE #SQL nvarchar(max)
SELECT #SQL = ' SELECT Col1 AS '+ Col1 +', Col2 AS '+ Col2 +', Col3 AS '+ Col3 +
' FROM DataTable'
FROM ColumnsTable
WHERE Id = 0
EXEC (#SQL)

Related

Split a column in T-SQL

I'm new to using T-SQL,
how do you separate an NVARCHAR column with the following information
[3293,"Maria","CA","Auto"]
[67093,"Joana","WA","Manual"]
I would like to get 4 columns like this
col1 col2 col3 col4
3293 Maria CA Auto
67093 Joana WA Manual
Thanks
Without the need for an aggregation.
Example
Select Col1 = JSON_VALUE([SomeCol],'$[0]')
,Col2 = JSON_VALUE([SomeCol],'$[1]')
,Col3 = JSON_VALUE([SomeCol],'$[2]')
,Col4 = JSON_VALUE([SomeCol],'$[3]')
From YourTable A
Results
Col1 Col2 Col3 Col4
3293 Maria CA Auto
67093 Joana WA Manual
You can use openjson and aggregate:
select
max(case when [key] = 0 then value end) col1,
max(case when [key] = 1 then value end) col2,
max(case when [key] = 2 then value end) col3,
max(case when [key] = 3 then value end) col4
from OpenJson('[3293,"Maria","CA","Auto"]')
One more suggestion uses a trick to stuff a json array into another array. This allows for a type-safe(!) and pivot/aggregate-free WITH-clause:
Declare a dummy table to provide a showcase (please do this yourself in your next question).
DECLARE #dummyTable TABLE(ID INT IDENTITY, YourJson NVARCHAR(MAX));
INSERT INTO #dummyTable(YourJson) VALUES
('[3293,"Maria","CA","Auto"]')
,('[67093,"Joana","WA","Manual"]');
--the query
SELECT t.ID
,JsonValues.*
FROM #dummyTable t
CROSS APPLY OPENJSON(CONCAT('[',t.YourJson,']'))
WITH
(
TheNumber int '$[0]'
,Firstname nvarchar(100) '$[1]'
,[State] nvarchar(100) '$[2]'
,[Type] nvarchar(100) '$[3]'
) JsonValues;
The idea in short:
Using CONCAT() we add a [ and a ] around your array.
Now we can use WITH specifying the resulting column with name, type and the json path to grab it.
The result:
+----+-----------+-----------+-------+--------+
| ID | TheNumber | Firstname | State | Type |
+----+-----------+-----------+-------+--------+
| 1 | 3293 | Maria | CA | Auto |
+----+-----------+-----------+-------+--------+
| 2 | 67093 | Joana | WA | Manual |
+----+-----------+-----------+-------+--------+
Use 'OpenJson' and pass the column values in a loop.
--Step1: Create a Temporary table and add Row_Number
select ROW_NUMBER() over( order by COL) as r,*
INTO #Temp_table
from YourTable;
--Step2: Declare and set Variables
DECLARE #count INT;
DECLARE #row INT;
DECLARE #JSON NVARCHAR(250);
set #count= (select COUNT(1) FROM #Temp_table);
SET #row = 1;
--Step3: Create Final table (Here, using temp final table)
CREATE TABLE #TEMP_FINAL
(COL1 INT,COL2 VARCHAR(100),COL3 VARCHAR(100),COL4 VARCHAR(100));
--Step4: Iterate over loop
WHILE (#row <= #count) BEGIN
SELECT #JSON=COL FROM #Temp_table WHERE #row=r;
INSERT INTO #TEMP_FINAL
select
max(case when [key] = 0 then value end) col1,
max(case when [key] = 1 then value end) col2,
max(case when [key] = 2 then value end) col3,
max(case when [key] = 3 then value end) col4
from OpenJson(#JSON);
SET #row += 1;
END
--Step5: Select the values
SELECT * FROM #TEMP_FINAL
To have understanding, you can review following links
Row_Number: https://www.sqlservertutorial.net/sql-server-window-functions/sql-server-row_number-function/
While Loop: https://www.sqlshack.com/sql-while-loop-with-simple-examples/

SQL pivot table1 into table2 without using dynamic SQL pivot or hardcode query

I have seen many questions and answers given about pivoting table with SQL, with dynamic SQL pivot or hard code query with CASE WHEN.
However is there any way I can pivot table without using those 2?
Table 1:
| col1 | col2 | col3 |
|--------|-------|--------|
| ABCD | 1 | XY123 |
| ABCD | 2 | RT789 |
| PQST | 3 | XY123 |
| PQST | 4 | RT789 |
Pivoting to
| col1 | ABCD | PQST |
|--------|-------|-------|
| XY123 | 1 | 3 |
| RT789 | 2 | 4 |
My idea was to retrieve the structure of the col with:
WITH
structure AS (
SELECT DISTINCT
col3 AS col1, col1 AS colName, col2 AS values
FROM table1 ori
)
and then extracting matched values of each cell with joins and storing them temporarily. At last JOIN again populating them in the output. However I am stuck after the above step. I can't use PIVOT and have to do this dynamically (i.e. can't use the method to hardcode each value with CASE WHEN)
How can I achieve this?
This is not as efficient (and not as easy to code) as a dynamic pivot. However, it is doable.
It does all need to be dynamic e.g., creating each SQL statement as a string and executing that.
The process involves
Determine the column names (store in a temporary table)
Creating the table with the first column only
Populating that first column
For each additional column name
Adding a column to the table (dynamically)
Populating that column with data
You haven't specified the database - I'll illustrate the following below using SQL Server/T-SQL.
The following are in this db<>fiddle so you can see what's going on.
CREATE TABLE #ColNames (ColNum int IDENTITY(1,1), ColName nvarchar(100), ColNametxt nvarchar(100));
INSERT INTO #ColNames (ColName, ColNametxt)
SELECT DISTINCT QUOTENAME(Col1), Col1
FROM table1;
This will populate the #ColNames table with the values 1, [ABCD], ABCD, 2, [PQST], PQST.
The next step is to create your output table - I'll call it #pvttable
CREATE TABLE #pvttable (col1 nvarchar(100) PRIMARY KEY);
INSERT INTO #pvttable (col1)
SELECT DISTINCT Col3
FROM table1;
This creates your table with 1 column (col1) with values XY123 and RT789).
The write your favorite loop (e.g., cursor, while loop). In each step
Get the next column name
Add the column to the table
Update that column with appropriate data
e.g., the following is an illustrative example with your data.
DECLARE #CustomSQL nvarchar(4000);
DECLARE #n int = 1;
DECLARE #ColName nvarchar(100);
DECLARE #ColNametxt nvarchar(100);
SELECT #ColName = ColName,
#ColNameTxt = ColNameTxt
FROM #ColNames
WHERE ColNum = #n;
WHILE #ColName IS NOT NULL
BEGIN
SET #CustomSQL = N'ALTER TABLE #pvttable ADD ' + #ColName + N' nvarchar(100);';
EXEC (#CustomSQL);
SET #CustomSQL =
N'UPDATE #pvttable SET ' + #Colname + N' = table1.col2'
+ N' FROM #pvttable INNER JOIN table1 ON #pvttable.col1 = table1.col3'
+ N' WHERE table1.col1 = N''' + #ColNametxt + N''';';
EXEC (#CustomSQL);
SET #n += 1;
SET #ColName = NULL;
SET #ColNametxt = NULL;
SELECT #ColName = ColName,
#ColNameTxt = ColNameTxt
FROM #ColNames
WHERE ColNum = #n;
END;
SELECT * FROM #pvttable;

SQL server trigger concat

I'm trying to write a SQL Server trigger that concats 3 columns, but inserts a string in place of the third column based on a condition.
For example when col 1 is inserted concat col 1, col 2 and col 3. But when col 3 = 'DR' concat Drive or col 3 = 'ST' concat Street etc.
I can write the trigger for all 3 columns, but having trouble with the conditional.
CREATE TRIGGER updateAddress
ON [ARCHIVENEW].dbo.a11
AFTER UPDATE
AS BEGIN
SET NOCOUNT ON;
IF UPDATE(STRNAME)
SELECT CASE
WHEN a11.STRTYPE = 'DR' THEN dbo.a11.STRFNAME = cast(dbo.a11.STRADDLF as varchar(2)) + ' ' + STRNAME + ' ' + 'Drive'
WHEN a11.STRTYPE = 'RP' THEN dbo.a11.STRFNAME = cast(dbo.a11.STRADDLF as varchar(2)) + ' ' + STRNAME + ' ' + 'Ramp'
WHEN a11.STRTYPE = 'EX' THEN dbo.a11.STRFNAME = cast(dbo.a11.STRADDLF as varchar(2)) + ' ' + dbo.a11.STRNAME + ' ' + 'Express Way'
ELSE dbo.a11.STRFNAME = cast(dbo.a11.STRADDLF as varchar(2)) + ' ' + dbo.a11.STRNAME
END
Sorry it took a few days to get back to this and add the code sample. I'm getting a syntax error near the '=' where I try and set my STRFNAME to the concatenated string. To clarify further, col1 is "1234" col2 is "Main" and col3 is "ST". When a row is inserted I'd like col4 to say "1234 Main Street".
Sample table:
CREATE TABLE dbo.TestTable(
Id INT IDENTITY(1,1) PRIMARY KEY
ColA VARCHAR(50),
ColB VARCHAR(50),
ColC VARCHAR(50),
ColD VARCHAR(50)
);
This trigger concats values of ColA, ColB for ColC and validates ColB value for ColD.
CREATE TRIGGER TestTable_UpdateTwoColumns
ON dbo.TestTable
AFTER INSERT,UPDATE
AS
BEGIN
SET NOCOUNT ON;
IF UPDATE(ColA)
BEGIN
UPDATE dbo.TestTable
SET ColC=new.ColA + new.ColB
FROM INSERTED new
END
IF UPDATE(ColB)
BEGIN
UPDATE dbo.TestTable
SET ColD=CASE new.ColB WHEN 'DR' THEN 'Drive' WHEN 'ST' THEN
'Street' END
FROM INSERTED new
END
END
Thanks,
You cannot change a table while the INSERT trigger is firing. You can, however, create a trigger before inserting the record.
CREATE TRIGGER emplog_update AFTER UPDATE ON emp
FOR EACH ROW
INSERT INTO emplog (id, lastnmae, firstname, . . .)
select NEW.id,NEW.lastname,NEW.firstname,NEW.gender,NEW.dob,NEW.marital,NEW.SSN,'U',NULL,USER(),
concat_ws(',',
(case when new.id <> old.id then 'id' end),
(case when new.lastname <> old.lastname then 'lastname' end),
(case when new.firstname <> old.firstname then 'firstname' end),
. . .
);
If your motto is insert into third column, good to use computed column. Here is an example. But as in my comment on question, I did not understand, how col3 value comes?
For this, I used col4 to get the proper result, also in computed column define, it not take reference of own.
CREATE TABLE dbo.Products
(
ProductID int IDENTITY (1,1) NOT NULL
, col1 varchar(50)
, col2 varchar(50)
, col3 varchar(50)
, col4 AS case col3 when 'DR' then 'Drive' when 'ST' then 'Street' else col1 + col2 end
--while computed column define, you can use all other column, except own.
);
-- Insert values into the table.
INSERT INTO dbo.Products (col1, col2,col3)
VALUES ('a', 'a1','a2'), ('b', 'b1', 'DR'), ('c', 'c1', 'ST'), ('d', 'd1', 'd2');
-- Display the rows in the table.
SELECT ProductID, col1, col2, col3, col4
FROM dbo.Products;
select * from products
drop table products

Apply conditions in projection level

Is there a simple way to apply conditions in projection level? I mean In a series of fields(columns) how can we choose only the fields those have specific conditions?
Example:
Assume we have a query with below result:
Id Col1 Col2 Col3 Col4 Col5 Col6 Col7 Col8 Col9 Col10 Col11
- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ----
1 V1_1 NULL NULL V4_1 NULL NULL NULL NULL NULL V10_1 NULL
2 V1_2 NULL NULL NULL NULL NULL NULL NULL NULL V10_2 NULL
3 V1_3 NULL NULL V4_3 NULL NULL NULL NULL NULL V10_3 NULL
how can we select only the fields which contains none null values while we don't know which of them contains none null values? so result would be this:
Id Col1 Col4 Col10
- ---- ---- ----
1 V1_1 V4_1 V10_1
2 V1_2 NULL V10_2
3 V1_3 V4_3 V10_3
Usually I do such these queries with hardcoding which I may query sys.all_obejcts, sys.all_columns in MsSQL Server and all_tab_cols, all_tables , etc in Oracle. and use none, one or more cursors , case statements, pivot, multiple ifs or dynamic sql in it.
in example: for a table with above data in T-SQL I can do:
DECLARE #sql VARCHAR(500)
SET #sql='SELECT Id,'
IF EXISTS (SELECT Col1 FROM tblTEST WHERE Col1 IS NOT NULL) SET #sql=#sql+'Col1,'
/* 9 other IF statements here */
IF EXISTS (SELECT Col11 FROM tblTEST WHERE Col11 IS NOT NULL) SET #sql=#sql+'Col11,'
SET #sql=SUBSTRING(#sql,1,LEN(#sql)-1)+' FROM tblTEST'
EXEC(#sql)
but as you see the idea is not common at all and it's a little hard to do such coding for such these scenarios
Do you know a simple and better way or a pattern for such this queries?
The RDBMS does not matter, a good solution for any RDBMS is really useful.
Please I want answers to be a good idea in general not only for the example I mentioned.
This is a T-SQL solution. All you should have to do is change #TargetTable to your desired table. Hope this helps! I commented my code explaining everything, but if you have any questions, let me know!
IF OBJECT_ID('myTable') IS NOT NULL
DROP TABLE dbo.myTable;
CREATE TABLE myTable
(
ID INT IDENTITY(1,1),
Col1 VARCHAR(25),
Col2 VARCHAR(25),
Col3 VARCHAR(25)
)
INSERT INTO dbo.myTable(Col1,Col2,Col3)
VALUES ('v1_1',NULL,NULL),
('v1_2','v2_2',NULL),
('v1_3',NULL,NULL);
/* Now that I've set up the problem, here's for the actual code*/
--Set your desired table
DECLARE #TargetTable VARCHAR(100) = 'myTable'
--If this global temp table exists, drop it
IF OBJECT_ID('##tempTable') IS NOT NULL
EXEC('DROP TABLE ##tempTable');
--This is going to take one character and cast it to NCHAR(1)
--If there are no characters, it will simply return NULL
DECLARE #AllColumns VARCHAR(MAX);
SELECT #AllColumns = COALESCE(#AllColumns + ',','') + 'CAST(LEFT(' + QUOTENAME(COLUMN_NAME) + ',1) AS NCHAR(1)) AS ' + QUOTENAME(COLUMN_NAME)
FROM INFORMATION_SCHEMA.COLUMNS A
WHERE TABLE_NAME = #TargetTable
/*Load your char results into a global temp table*/
EXEC('SELECT ' + #AllColumns + ' INTO ##tempTable FROM ' + #TargetTable);
/*Here's where the fun beings*/
/* #DesiredCol holds the name of columns that are not null.
UNPIVOT the data.
Where clause gets rid of columns with only NULL values.
Group by only allows distinct columns.
You the select from your ORIGINAL table, not my funky nchar(1) global temp table.
*/
EXEC(
'DECLARE #DesiredCol VARCHAR(MAX);
SELECT #DesiredCol = COALESCE(#DesiredCol + '','','''') + QUOTENAME(col)
FROM ##temptable
UNPIVOT
(
val FOR col IN ([ID],[Col1],[Col2],[Col3])
) pvt
WHERE pvt.val IS NOT NULL
GROUP BY col
EXEC (''SELECT '' + #DesiredCol + '' FROM ##' + #TargetTable + ''')'
)
--Cleanup
IF OBJECT_ID('##tempTable') IS NOT NULL
EXEC('DROP TABLE ##tempTable');

Stored procedure setting a value if row is empty

How would I go about setting a value if a row is empty ('')?
I was thinking something like,
Got var with default value called #defaultValue to set it where the row in a table is ''.
if (select col1 from table1 where col1 = '')
set (select col1 from table1 where col1 = '') = #DefaultValue
is there a better way?
code is just a draft its not even tested..
If you want to update the table with #DefaultValue, you can use WHERE clause in the UPDATE query:
UPDATE table1
SET col1=#DefaultValue
WHERE col1=''
OR col1 IS NULL
OR
If you are trying to select #DefaultValue if the column is empty or null, you can do this:
SELECT CASE WHEN (col1 IS NULL OR col1='')
THEN #DefaultValue
ELSE col1
END AS Col1
FROM table1
select case when col1 ='' then #DefaultValues else col1 end from table
DEMO
declare #default int
set #default=1
declare #tbl table(col1 int)
insert into #tbl values(1),(''),(2)
select case when col1='' or col1 is null then #default else col1 end from #tbl