Create table from rows of another table along with its properties - sql

I have a table named Table1
Column Name Data type Max length Precision Scale is_nullable Primary Key
Price float 8 53 0 1 0
Name varchar 180 0 0 1 0
Id_no int 4 10 0 1 1
DOB date 3 10 0 1 0
I need to create another table named Table2 where the Column Name rows of table 1 (along with the properties such as Data Type, Max Length etc.,) should be my columns of another table, like
Table 2
Price Name Id_No DOB
(Please note that create table query should also take into account of the properties)

You can create a copy of a table with select into:
select *
into NewTable
from OldTable

create table table2
as
select * form table1;

You can dynamically create a SQL statement and then run that command.
DECLARE #dsql nvarchar(max) = N''
SELECT #dsql += QUOTENAME([Column Name]) + ' ' +
[Data type] +
+ CASE WHEN [Data type] = 'varchar'
THEN '(' + CAST([Max length] AS nvarchar(4)) + ')' ELSE '' END + ','
FROM Table1
SELECT #dsql = 'CREATE TABLE Table2 (' + LEFT(#dsql, LEN(#dsql) - 1) + ')'
EXEC sp_executesql #dsql

Related

Making columns from one column's data in SQL Server

I have a SQL Server table like this
ID amount type
1 10 material
1 5 spare parts
1 5 material
I need to make a query and get outputs like this
ID material spare parts
1 15 5
But I have too many IDS and types, so I need to add items dynamically whatever their count.
You are looking for a dynamic pivot. Basically this works selecting the list of types from the table, then building a query from that information. You can then execute the query with sp_executesql.
For your table structure:
declare #sql nvarchar(max);
select #sql = string_agg(
'sum(case when type = ''' + type + ''' then amount else 0 end) [' + type + ']',
', ')
from (select distinct type from mytable) t;
set #sql = N'select id, ' + #sql + ' from mytable group by id';
select #sql; -- debug
-- exec sp_executesql #sql; -- execute for real
For your sample data, this generates the following query (I added line breaks added for readability):
select
id,
sum(case when type = 'material' then amount else 0 end) [material],
sum(case when type = 'spare parts' then amount else 0 end) [spare parts]
from mytable
group by id
After execution, you get result:
id | material | spare parts
-: | -------: | ----------:
1 | 15 | 5
Demo on DB Fiddle

Creating a TABLE to pivot and concat columns from exiting table?

I have a Table that stores customer Dynamic values from the Forms that they create.
The Table is called Dynamic_Fields_T and is formatted like this:
ID | FIELD_NAME
1 | TANK
2 | PRODUCT TYPE
3 | ODOMETER
4 | RECEIPT #
This is not joinable to our ticket Tables.
I need this to appear like this:
ID_1 | ID_2 .......ID_N
TANK | PRODUCT_TYPE ......N
Any Help is appreciated.
Assuming that your [ID] column is unique you can use a dynamic select statement with an aggregation function (min or max) to return all your rows in a single row:
--create test table
create table #Dynamic_Fields_T (
[ID] INT
,[FIELD_NAME] varchar(max)
)
--populate test table
insert into #Dynamic_Fields_T
values
(1 ,'TANK')
,(2 ,'PRODUCT TYPE')
,(3 ,'ODOMETER')
,(4 ,'RECEIPT #')
declare #sql nvarchar(max) =''
--build dynamic columns
select
#sql = #sql + ',max(case when [ID] = ''' + cast([ID] as varchar) + ''' then [FIELD_NAME] end) as [ID_' + cast([ID] as varchar) + ' ] '
from
#Dynamic_Fields_T
--build dynamic query, remove unnecessary comma
select #sql = 'select ' + stuff(#sql, 1 , 1, '') + ' from #Dynamic_Fields_T'
--execute dynamic query
execute (#sql)
result:

One view from two tables with identical column names

We have two tables that we need to merge into a singular view. Normally I'd individually select columns to avoid this issue, however in this case the two tables are a combined 800 columns.
The only identical columns are the identifier columns. Unfortunately these cannot be changed as they are used by a 3rd party tool to sync table
Table A
GUID
Name
Address
...
Table B
GUID
Cell
Fax
Home2
...
Are good examples, just assume each table has 400 odd columns.
Obviously the traditional
SELECT a.*, b.* from table_a a, table_b a where a.guid = b.guid
Fails miserably. Is there any easy way to create the view without having to list out 799 individual column names? I was thinking perhaps a one off function to create the view but so far I'm hitting a wall.
You can use dynamic sql as a solution.
CREATE TABLE test1 (id INT, col1 NVARCHAR(50), col2 NVARCHAR(50))
GO
CREATE TABLE test2(id INT, col1 NVARCHAR(50), col2 NVARCHAR(50))
GO
DECLARE #sql NVARCHAR(max) = ''
; WITH cte AS (
SELECT
CASE WHEN TABLE_NAME = 'test1' THEN TABLE_NAME + '.' + COLUMN_NAME + ' AS ' + + COLUMN_NAME + 't1' ELSE TABLE_NAME + '.' + COLUMN_NAME + ' AS ' + + COLUMN_NAME + 't2' END AS a, 1 AS ID
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME IN ('test1', 'test2')
)
SELECT #sql =
'CREATE VIEW myview as
select ' + (
SELECT
STUFF(
(
SELECT ', '+ [A]
FROM cte
WHERE ID = results.ID
FOR XML PATH(''), TYPE
).value('(./text())[1]','VARCHAR(MAX)')
,1,2,''
) AS NameValues
FROM cte results
GROUP BY ID
) + ' from test1 join test2 on test1.id = test2.id'
PRINT #sql
--EXEC (#sql)
The result is
CREATE VIEW myview
AS
SELECT test1.id AS idt1 ,
test1.col1 AS col1t1 ,
test1.col2 AS col2t1 ,
test2.id AS idt2 ,
test2.col1 AS col1t2 ,
test2.col2 AS col2t2
FROM test1
JOIN test2 ON test1.id = test2.id

Dynamic pivot data with multiple datatypes

I have a trick problem with a pivot table to make:
I have a table which looks like:
id table object name type nvarchar date int bit
1 1 2 name 1 tables NULL NULL NULL
2 1 2 name 1 columns NULL NULL NULL
3 1 2 name 1 datatypes NULL NULL NULL
4 1 2 name 1 _users NULL NULL NULL
1 1 3 active 3 NULL NULL NULL 1
2 1 3 active 3 NULL NULL NULL 1
3 1 3 active 3 NULL NULL NULL 1
4 1 3 active 3 NULL NULL NULL 1
the output should look like:
id name active
1 tables 1
2 columns 1
3 datatypes 1
4 _users 1
Based upon the "type" I should put the correct data from the column in it, these columns are formated in nvarchar, bit, datetime, int, ect.
The "id" is the row id, the "name, active" comes from the name column and the values from nvarchar, date, int and bit columns.
UPDATE: the columns like nvarchar, date, int and bit (and most other SQL formats) are actually contain this type of data. The column "type" gives which column contains the data to being used, so if "type" is "1", than I want to use the "nvarchar" if "type" is "3" than I want to use the "bit" which contains really a bit and not a nvarchar. In the Pivot I want to have the bit under "active" column, if I have in the example a 3th column (name) for example "activation_date" I want to see a third column with the value (type = 2) from the date column.
I am lost in this, please help
Assuming there's only one not null column for each row:
with cte as (
select
id,
name,
coalesce(
[nvarchar],
convert(nvarchar(max), [date], 120),
cast([int] as nvarchar(max)),
cast([bit] as nvarchar(max))
) as value
from Table1 as t
)
select
id,
max(case when [name] = 'name' then value end) as [name],
max(case when [name] = 'active' then value end) as [active]
from cte
group by id
sql fiddle demo
But I must warn you, this types of database schema is not best way to use SQL.
If you want to do this dynamically without hardcoding columns:
declare #stmt nvarchar(max)
select #stmt =
isnull(#stmt + ', ', '') +
'max(case when [name] = ''' + name + ''' then value end) as ' + quotename([name])
from (select distinct [name] from Table1) as t
select #stmt = '
with cte as (
select
id,
name,
coalesce(
[nvarchar],
convert(nvarchar(max), [date], 120),
cast([int] as nvarchar(max)),
cast([bit] as nvarchar(max))
) as value
from Table1 as t
)
select
id, ' + #stmt + '
from cte
group by id
'
exec sp_executesql
#stmt = #stmt
sql fiddle demo
If you have some Mapping table like this:
name value
--------------------
name nvarchar
active bit
you can use this query:
declare #stmt nvarchar(max)
select #stmt =
isnull(#stmt + ', ', '') +
'max(case when [name] = ''' + name + ''' then [' + value + '] end) as ' + quotename([name])
from Mapping
select #stmt = '
select
id, ' + #stmt + '
from Table1
group by id
'
exec sp_executesql
#stmt = #stmt
sql fiddle demo

Access columns of a table by index instead of name in SQL Server stored procedure

Is there a way to access columns by their index within a stored procedure in SQL Server?
The purpose is to compute lots of columns. I was reading about cursors, but I do not know how to apply them.
Let me explain my problem:
I have a row like:
field_1 field_2 field_3 field_4 ...field_d Sfield_1 Sfield_2 Sfield_3...Sfield_n
1 2 3 4 d 10 20 30 n
I need to compute something like (field_1*field1) - (Sfield_1* Sfiled_1) / more...
So the result is stored in a table column d times.
So the result is a d column * d row table.
As the number of columns is variable, I was considering making dynamic SQL, getting the names of columns in a string and splitting the ones I need, but this approach makes the problem harder. I thought getting the column number by index could make life easier.
No, you can not use the ordinal (numeric) position in the SELECT clause.
Only in the ORDER BY clause can you use the ordinal position, because it's based on the column(s) specified in the SELECT clause.
First, as OMG Ponies stated, you cannot reference columns by their ordinal position. This is not an accident. The SQL specification is not built for dynamic schema either in DDL or DML.
Given that, I have to wonder why you have your data structured as you do. A sign of a mismatch between schema and the problem domain rears itself when you try to extract information. When queries are incredibly cumbersome to write, it is an indication that the schema does not properly model the domain for which it was designed.
However, be that as it may, given what you have told us, an alternate solution would be something like the following: (I'm assuming that field_1*field1 was meant to be field_1 * field_1 or field_1 squared or Power( field_1, 2 ) )
Select 1 As Sequence, field_1 As [Field], Sfield_1 As [SField], Sfiled_1 As [SFiled]
Union All Select 2, field_2, Sfield_2, Sfiled_2
...
Union All Select n, field_n, Sfield_n, Sfiled_n
Now your query looks like:
With Inputs As
(
Select 1 As Sequence, field_1 As [Field], Sfield_1 As [SField], Sfiled_1 As [SFiled]
Union All Select 2, field_2, Sfield_2, Sfiled_2
....
)
, Results As
(
Select Case
When Sequence = 1 Then Power( [Field], 2 ) - ( [SField] * [SFiled] )
Else 1 / Power( [Field], 2 ) - ( [SField] * [SFiled] )
End
As Result
From Inputs
)
Select Exp( Sum( Log( Result ) ) )
From Results
This might not be the most elegant or efficient but it works. I am using it to create a new table for faster mappings between data that I need to parse through all the columns / rows.
DECLARE #sqlCommand varchar(1000)
DECLARE #columnNames TABLE (colName varchar(64), colIndex int)
DECLARE #TableName varchar(64) = 'YOURTABLE' --Table Name
DECLARE #rowNumber int = 2 -- y axis
DECLARE #colNumber int = 24 -- x axis
DECLARE #myColumnToOrderBy varchar(64) = 'ID' --use primary key
--Store column names in a temp table
INSERT INTO #columnNames (colName, colIndex)
SELECT COL.name AS ColumnName, ROW_NUMBER() OVER (ORDER BY (SELECT 1))
FROM sys.tables AS TAB
INNER JOIN sys.columns AS COL ON COL.object_id = TAB.object_id
WHERE TAB.name = #TableName
ORDER BY COL.column_id;
DECLARE #colName varchar(64)
SELECT #colName = colName FROM #columnNames WHERE colIndex = #colNumber
--Create Dynamic Query to retrieve the x,y coordinates from table
SET #sqlCommand = 'SELECT ' + #colName + ' FROM (SELECT ' + #colName + ', ROW_NUMBER() OVER (ORDER BY ' + #myColumnToOrderBy+ ') AS RowNum FROM ' + #tableName + ') t2 WHERE RowNum = ' + CAST(#rowNumber AS varchar(5))
EXEC(#sqlCommand)