I am working on SQL Server 2016.
I want to know is there anyway I can create a permanent or temporary table with column names present in another table?
See the table: MAINTAGS and its code below. I want DOB as my first column, POB as 2nd and so on...
Currently there are 12 names in my MAINTAGS table, so new table will have total 12 columns.
More names can be added as well in MAINTAGS
ID_MAINTAGS NAMES_MAINTAGS
============== ==============
1 DOB
2 POB
3 citizen
4 nationality
5 Additional Sanctions Information
6 Passport
7 National ID No.
8 Email Address
9 Gender
10 a.k.a.
11 Linked To:
12 Phone Number
IF OBJECT_ID('dbo.MAINTAGS', 'U') IS NOT NULL
DROP TABLE dbo.MAINTAGS;
CREATE TABLE MAINTAGS(ID_MAINTAGS INT IDENTITY(1,1), NAMES_MAINTAGS VARCHAR(MAX));
INSERT INTO MAINTAGS (NAMES_MAINTAGS)
VALUES
('DOB'),('POB'),('citizen'),('nationality'),
('Additional Sanctions Information'), ('Passport'),('National ID No.'),
('Email Address'),('Gender'),('a.k.a.'),('Linked To: ')
Let me start by stating that this smells strongly of an XY Problem and the fact you want to do this very strongly suggests a design flaw.
I'm also going to assume that you have something that defines the data type; I'm going for some columns with the data type, length, precision and scale properties. If you don't have this, add them.
Anyway, you can achieve this with some simple string aggregation, and then execute the dynamic statement:
DECLARE #SchemaName sysname = N'dbo',
#TableName sysname = N'NewTableName';
DECLARE #SQL nvarchar(MAX),
#CRLF nchar(2) = NCHAR(13) + NCHAR(10);
DECLARE #Delimiter = N',' + #CRLF;
SELECT #SQL = N'CREATE TABLE ' + QUOTENAME(#SchemaName) + N'.' + QUOTENAME(#TableName) + N'(' + #CRLF +
STRING_AGG(N' ' + QUOTENAME(YT.ColumnName) + N' ' + QUOTENAME(YT.DataType) +
CASE WHEN YT.Length IS NOT NULL OR YT.Precision IS NOT NULL OR YT.Scale IS NOT NULL THEN N' (' + CONCAT_WS(',',YT.Length,YT.Precision,YT.Scale) + N')' ELSE N'' END,#Delim)
FROM dbo.YourTable YT;
--PRINT #SQL --Your best friend.
EXEC sys.sp_executesql #SQL;
Note that in your example the column NAMES_MAINTAGS allows up to ~2 billion characters; object names cannot be this long. As a result these values will be truncated to 128 characters; if you therefore have duplicate names due to this, the CREATE statement will fail.
Related
We have a View in SQL Server that constantly evolving.
We want to show it in a report as it is (If we add/remove a field in the View, we don't have to modify the report and add/remove manuelly the field).
A sort of a table/matrix that is refreshing by itself.
Thank you by advance for your help.
Without using a table or matrix? Why not? You can't really do this without using one of these controls...
Ignoring that for a moment though, the problem you will face is that the dataset query has to always return the same structure every time it is run so you can't point it directly at a query that is constantly changing.
The only way you might be able to do this is to write a query that unpivots your table/view into another structure and then report on that. By using a matrix, you could reconstruct the table in the report.
There are drawbacks to this approach. All value data needs to be cast to a constant datatype so if each row has a mix of text and numeric values, they would all have to be converted to text.
This approach also assumes there is a key column on the table/view.
Below is a simple example of the kind of thing I mean. This is based on the sample 'AdventureWorksDW2016' database in case you want to test it.
DECLARE #Schema sysname = 'dbo' -- Schema where table/view resides
DECLARE #Table sysname = 'DimGeography' -- name of table or view to read from
DECLARE #KeyColumn sysname = 'GeographyKey' -- name of keycolumn, assumed to be INT in this exmaple
SELECT
COLUMN_NAME, ORDINAL_POSITION, DATA_TYPE
into #t
FROM INFORMATION_SCHEMA.COLUMNS t
WHERE TABLE_SCHEMA = #Schema AND TABLE_NAME = #Table
AND COLUMN_NAME != #KeyColumn
DECLARE #OrdPos int
DECLARE #ColName sysname
DECLARE #sql varchar(max) = ''
CREATE TABLE #result (KeyID int, ColumnName sysname, ColumnPosition int, ColumnValue varchar(75)) -- <= Update 75 to suit maximum column length
WHILE EXISTS(SELECT * FROM #t)
BEGIN
SELECT TOP 1 #OrdPos = ORDINAL_POSITION, #ColName = COLUMN_NAME FROM #t
SET #SQL = 'INSERT INTO #result SELECT ' + #KeyColumn + ', ''' + #ColName + ''', ' + CAST(#OrdPos as varchar(10)) + ', CAST(' + #ColName + ' as varchar(200)) FROM ' + QUOTENAME(#Schema) + '.' + QUOTENAME(#Table)
EXEC (#sql)
DELETE FROM #t WHERE ORDINAL_POSITION = #OrdPos
END
SELECT * FROM #result
If we take a look at the results (just for 2 keyid vales for simplicity) we can see we have a consistent structure.
SELECT * FROM #result where keyid in (207,208) order by KeyID, ColumnPosition
Now, you can build a simple report using a Matrix, have a row group that groups by KeyID and have a column group that groups by ColumnName. The column group sorting can be set to ColumnPosition and the matrix 'data' cell set to ColumnValue.
This whole process will effectively recreate the table/view and be dynamic.
I am trying to dynamically insert data into a temp table passing like data as a variable:
DECLARE #data NVARCHAR(MAX)
SET #data = 'INSERT INTO #coco ' + '([' + #val + '])' + ' SELECT [USER_ID] FROM [dbo].[Sheet1$] WHERE [Standard_Name] LIKE ' + #val
EXEC sp_executesql #data
#val is a column name selected from table Sheet1$ and few column name has space between them. While executing, I am getting error, like for column name "Acrobat Reader":
Incorrect syntax near 'Acrobat'.
Also if I am adding data using hardcoded one by one in a column its adding data to one column while other column its adding NULL.
Any suggestion how I can overcome this?
Parametrise your SQL, and this problem "goes away":
DECLARE #data;
SET #data = N'INSERT INTO #Coco (' QUOTENAME(#val) + N')' + NCHAR(10) +
N'SELECT [USER_ID]' + NCHAR(10) +
N'FROM dbo.[Sheet1$]' + NCHAR(10) +
N'WHERE [Standard_Name] = #val;'; --As this doesn't contain a %, there's no need for LIKE
EXEC sp_executesql #data,
N'#val = sysname', --guessed datatype
#val = #val;
Note the comments I made in the SQL though.
Afraid, I've no idea what your second statement means. You'll need to explain further.
Say i have columns PlanSalesMt1, PlanSalesMt2 and so on for the whole year until Mt12 in a table.
Before i created a view where i unioned all the months togheter but that query is pretty slow. Now i want to try the query with a Loop.
My Problem is i can't use the variable in my column names because they get invalid. Is that a way to solve this?
What i mean is i want to loop my question 12 times and change the name of the columns also after what month it is. But i cant make a #i variable and say select PlanSalesMt#1 or PlanSalesMt+#1 or PlanSalesMt+CAST(#1 as varchar) becuase it says invalid column Name.
Here is an example of dynamic SQL
DECLARE #ColumnName1 VarChar(20)
DECLARE #ColumnName2 VarChar(20)
DECLARE #sql Varchar(1000)
DECLARE #MyWhere VarChar(20)
SET #ColumnName1 = 'PlanSalesMt1'
SET #ColumnName2 = 'PlanSalesMt2'
SET #MyWhere = 'Books'
SET #sql = 'SELECT ' + #ColumnName1 + ', ' + #ColumnName2 + ' FROM TABLE WHERE ' + #ColumnName1 + ' = ''' + #MyWhere + ''''
EXEC(#sql)
If you change EXEC(#sql) to SELECT #sql copy into SSMS and run it you will see the query this produces.
I have a database that contains a lot of NCHAR(n) columns. Some of these columns are simple properties, but some are also primary-keys or foreign keys.
There are many tables and columns and a huge amount of test data.
What is the best way to convert every NCHAR(n) column to a NVARCHAR(n) column of the same length and trim its content while doing so?
If you can think of anything better than changing the column in the designer, remembering the column name and trimming it in a script window, please post it as an answer.
Something like this would do the trick I think (unless any are primary keys and then you will get an error - I would suggest that you manually do the primary keys in the designer in your case because to alter them you have to drop the constraints etc and that gets a bit tricky)...
It gets all the table names, column names and sizes for all the columns that are nchar and for each performs an alter statement to change the column type and then an update that trims the data.
There may be a more performant way to do it but if you are only doing it once perhaps this will be ok (oh, change the databaseName bit to the name of your database)...
use databaseName
declare #tn nvarchar(128)
declare #cn nvarchar(128)
declare #ln int
declare #sql as nvarchar(1000)
declare c cursor for
select table_name,column_name,character_maximum_length
from information_schema.columns
where data_type ='nchar' and
TABLE_NAME not in (select TABLE_NAME from INFORMATION_SCHEMA.VIEWS)
open c
fetch next from c into #tn, #cn, #ln
while ##FETCH_STATUS = 0
begin
set #sql = 'alter table ' + #tn + ' alter column '
+ #cn + ' nvarchar(' + convert(nvarchar(50), #ln) + ')'
exec sp_executesql #sql
set #sql = 'update ' + #tn + ' set ' + #cn + ' = LTRIM(RTRIM(' + #cn + '))'
exec sp_executesql #sql
fetch next from c into #tn, #cn, #ln
end
close c
deallocate c
Is there a script out there that will let MSSQL find columns with records that have the same data in multiple tables.
What I want to do is find the primary keys to data tables that we imported from excel spread sheets that were made from another database.
Thanks,
Chris
You're going to want to look up the SysObjects and SysColumn system tables, very handy for this sort of thing.
Here's an example that looks through all tables for the integer value 500. Note that if you want to look for a different type of column you'll need to change the xtype. It's not a full blown "Compare every column in my database against every other column" example however it should give you the basic idea and hopefully get you started.
Additionally I'm using a memory table for this example. If your database is large you will want to use a temporary table and a cursor likely.
This returns a single column recordset with the value of "Table - ColumnName = Search Value"
-- declare my search table
DECLARE #Columns TABLE (TableName varchar(50), ColumnName varchar(50))
DECLARE #Results TABLE (Results VARCHAR(255))
DECLARE #SearchData INT
SET #SearchData = 500
DECLARE #TableName VARCHAR(50)
DECLARE #ColumnName VARCHAR(50)
DECLARE #Command VARCHAR(1024)
-- Find all tables with an integer column
Insert INTO #Columns
Select sysobjects.[Name] as TableName, syscolumns.[Name] as ColumnName
from dbo.sysobjects INNER Join dbo.syscolumns ON dbo.sysobjects.id = dbo.syscolumns.id
Where sysobjects.xtype = 'U' and syscolumns.xtype = 56 Order By TableName, ColumnName
--Loop!
WHILE NOT (Select TOP 1 TableName from #Columns) IS NULL
BEGIN
Select TOP 1 #TableName = TableName, #ColumnName = ColumnName from #Columns
SET #Command = 'Select ''' + #TableName + ' - ' + #ColumnName + ' = ' + CAST(#SearchData as varchar(32)) + ''' FROM ' + #TableName + ' WHERE ' + #ColumnName + ' = ' + CAST(#SearchData as VARCHAR(32))
Insert INTO #Results
exec(#Command)
Delete from #Columns where TableName = #TableName AND ColumnName = #ColumnName
END
-- Export all results
Select * from #Results