Add column into Table through variable using SQL Server - sql-server

I have check unique value in the column VariantSKU using this sql code
alter Proc spIsUnique
#columnname nvarchar(max),
#tablename nvarchar(max)
As
Begin
EXEC ('select '+#columnname+',
IIf (count(*)>1,''False'',''True'') as Total
from '+#tablename+'
group by '+#columnname)
End
As you can see new column Total which contain True or False..
Now I want to add this column into the table in database. USing function it was not possible so I have created new table exactly same data called "Result" table.How can I add that column Total in Result table.
How can I do it?

if i understand well your question then use temp db to stock your table then join it with the destination table or do juste a union
alter Proc spIsUnique
#columnname nvarchar(max),
#tablename nvarchar(max)
As
Begin
= EXEC ('select '+#columnname+',
IIf (count(*)>1,''False'',''True'') as Total
into ##tempdb
from '+#tablename+'
group by '+#columnname)
End
select d.* , t.Total from destinationtable as d
inner join ##tempdb as t ON d.#columnname = t.#columnname

Related

Calculate the value of the expression after the join of the tables in SSIS

Table structure
Goal:
Is to calculate the value of the expression(They are the column names from the table).
Check whether the expression is correct and evaluate the result.
Expected and Actual results : Unable to evaluate the expression value with the help of SSIS. Failing at validation level when used in a query at OLE db source level.
Unable to get the value of expression at the granularity shown using SSIS components.
Trying to check by row by row debugging to flag the error expression value as bad. Trying not to run this in a batch. Looking to run it row by row to segregate the error rows.
Dynamic SQL will solve your problem.
Table Schema:
CREATE TABLE TableA(ColA INT,ColB VARCHAR(20),ColC INT,ColE INT)
INSERT INTO dbo.TableA VALUES(1,'US',2,1)
INSERT INTO dbo.TableA VALUES(1,'US',4,2)
INSERT INTO dbo.TableA VALUES(2,'IND',3,6)
INSERT INTO dbo.TableA VALUES(2,'IND',1,5)
CREATE TABLE TableB(ColX INT,ColY VARCHAR(20),ColZ VARCHAR(20),ColV VARCHAR(20))
INSERT INTO dbo.TableB VALUES(1,'US','ColC*ColE','Table1')
INSERT INTO dbo.TableB VALUES(2,'US','ColC/ColE','Table1')
Dynamic SQL Query:
DECLARE #query NVARCHAR(MAX)=''
SELECT #query = #query + '
UNION
SELECT A.ColA,
A.ColB,
A.ColC,
A.ColE,
B.ColZ AS ColF,
1.0*' +ColZ+ '
FROM TableA A
JOIN TableB B ON A.ColA = B.ColX
WHERE ColZ = ''' + ColZ + ''' '
FROM TableB;
SET #query = STUFF(#query,1,6,'');
--SELECT #query
--Print #query
EXEC (#query)
Check the output in the SQL Fiddle

Execute 2 queries that are in 2 variables and store the result in other 2 variables

As mentioned in the question, I want to store the results of these queries into other variables so that I can compare the output and find the ones which are not matching. Please help me out with it. The variable #Stagename consists of the first query and variable #correctname consists of the second query. I found some answers of storing them into a table variable but it is not working. These queries are not a single query and hence are stored in the form of rows of a table and are being fetched by the cursor. I've passed the second variable #tablename which I want as the final output but only of the ones in whom the comparison is not matching. I've used the following code:
DECLARE #Stagename VARCHAR(MAX)
DECLARE #correctname VARCHAR(MAX)
DECLARE #tablename VARCHAR(MAX)
--DECLARE #StageCount VARCHAR(max)
--DECLARE #IndexCount VARCHAR(MAX)
DECLARE #Table1 TABLE (StageCount Varchar(max), TableName VARCHAR(MAX))
DECLARE #Table2 TABLE (IndexCount Varchar(max), TableName VARCHAR(MAX))
--DEALLOCATE IF EXISTS CS_StagingIndex
DECLARE CS_StagingIndex CURSOR FOR
SELECT StageCount, CorrectCount, TableName FROM bak.StagingindexesQuery
OPEN CS_StagingIndex
FETCH NEXT FROM CS_StagingIndex
INTO #Stagename,#Correctname,#tablename
WHILE ##Fetch_Status = 0
BEGIN
INSERT INTO #Table1(StageCount,TableName) VALUES (exec(#StageName),#tablename);
INSERT INTO #Table2(IndexCount,TableName) VALUES (exec(#CorrectName),#tablename);
--Select * from #Table1 Ignore this.
FETCH NEXT FROM CS_StagingIndex
INTO #Stagename,#Correctname,#tablename
END
CLOSE CS_StagingIndex
DEALLOCATE CS_StagingCursor
Select count(1) from stg.LogisticsElectronicAddres - This is the query stored in #StageName.
select count(1) from (select distinct recid1 from stg.LogisticsElectronicAddress) x - This is the query stored in #IndexName.
LogisticsElectronicAddress and this is the tablename.
Now if for example, the result of StageName query is 2000 and the result of Correctname is also 2000, then the tablename should not be printed. But if the results dont match, then I want the tablename to be printed. There are multiple rows in bak.StagingIndexesQuery table that contain such queries for multiple tables.
I don't believe that's the correct EXEC syntax for sql-server; I don't think that is going to work.
What you can do is use the statement .. INSERT table EXEC storedprocName.
However, there are constraints - the table layout must match that of the return procedure in terms of column count/order/data types/length ( within reason, ie if a column in the table is NVARCHAR(100) and the stored procedure returns that column as NVARCHAR(105), that should be fine - unless of course the data itself exceeds the 100 length). I believe column names are ignored for INSERT/EXEC
Also, if the query being executed has an INSERT/EXEC , this will not work (only one allowed at anyone time)
So you will need to use dynamic SQL...
DECLARE #MySQLStatement NVARCHAR(400)
DECLARE #MyStoedProcName NVARCHAR(100)
DECLARE #Table1 TABLE (StageCount Varchar(max), TableName VARCHAR(MAX))
SET #MySQLStatement = 'INSERT #Tablename EXEC ' + #StoredProcedure
EXEC sp_ExecuteSQL #MySQLStatement
Now off the top of my head, I can't remember if that #Table1 will be in the scope of that dynamic SQL statement. If it isn't, make #Table1 a temp table (ie create table #table1 [ ... etc ] )

SQL Server 2012 split out multiple values in one varchar(1200)

In a SQL Server 2012 database, I am supposed to count the number of times each 'canned' message is used for elementary students in the last school year and the current school year.
Right now I have the following T-SQL that kind of works:
USE TEST
SELECT
GS.Comments, COUNT(*) AS [Counts]
FROM
dbo.Enrol Enrol
JOIN
dbo.Student Student ON Student.StudentID = Enrol.StudentID
JOIN
dbo.GS GS ON GS.StudentID = Student.Studentid
AND (GS.Comments IS NOT NULL)
AND (GS.Comments <> '')
WHERE
Enrol.grade IN ('KG', '01', '02', '03', '04', '05', '06')
AND Enrol.endYear BETWEEN 2016 AND 2017
GROUP BY
GS.Comments
ORDER BY
Counts DESC, GS.Comments ASC
The problem is the GS.Comments column is defined as varchar(1200). There can be one message in the column and/or there can be lots of messages in this column. Each message ends with a period and there is a space between each message.
An example of multiple messages in the one GS.Comments column would look like the following:
The student is trying hard and needs to make their time more efficiently. This student is good at math. This student turns in their assignments on time. This student seems to enjoy school.
An example of when one messages is in the one GS.Comments column would look like the following:
This student seems to enjoy school.
Thus would show me the T-SQL logic that I can use when the GS.Comments column contains multiple messages and/or just one message so that I can count the number of times each unique message has been used?
You can split your column on periods using the following link. then a simple group by on the newly formed column should let you count it.
Splitting delimited values in a SQL column into multiple rows
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
Alter proc [dbo].[StringSplitIntoRows]
(
#tbl varchar(100),---table name as parameter
#col varchar(100)---column name as parameter
)
As
Begin
--creating two temp tables
If OBJECT_ID('tempdb..#test1') is not null drop table #test1
create table #test1(tempcol varchar(200))
--inserting the table(has comma seperated string column) data into temp table
Declare #tempresult nvarchar(500)
set #tempresult = 'insert into #test1(tempcol) select ' + quotename(#col) + ' from ' + quotename(#tbl)
exec sp_executesql #tempresult
If OBJECT_ID('tempdb..#test2') is not null drop table #test2
create table #test2(tempcol1 varchar(200))
Declare #Name varchar(200)
Declare #real VARCHAR(100)
declare split cursor for ---declared a cursor to fetch row by row data
select tempcol from #test1 --temp table which has comma seperated string in column
open split
fetch next from split into #Name
while (##FETCH_STATUS=0)
Begin
declare #temp int=0
declare #result nvarchar(MAX)=''
declare #begin int=0
while CHARINDEX(',',#Name,#begin) > 0
begin
set #temp=CHARINDEX(',',#Name,#begin)
set #result=SUBSTRING(#Name,#begin,#temp-#begin)
set #begin=#temp+1
insert into #test2(tempcol1) values(#result)
end
set #real = SUBSTRING(#Name,#begin,len(#Name)-abs(#temp-#begin)+1)
insert into #test2(tempcol1) values(#real)
fetch next from split into #Name
End
select distinct tempcol1 from #test2
Close split
Deallocate split
end
GO
--execution
exec StringSplitIntoRows 'YourTableName','ColumnName'

SQL Server 2008 R2: Cursor with condition

I have the table which contains the table's id and name.
Now I want to retrieve the table names by passing table ID to the stored procedure.
Example:
create procedure spGetAllTables
#TableIDs varchar(max)
AS
DECLARE #Tables varchar(max)
DECLARE Cur1 CURSOR FAST_FORWARD FOR
SELECT TableName FROM TablesContainer
WHERE TableID IN (#TableIDs)
OPEN Cur1
FETCH NEXT FROM Cur1 INTO #Tables
WHILE(##FETCH_STATUS=0)
BEGIN
PRINT(#Tables)
FETCH NEXT FROM Cur1 INTO #Tables
END
CLOSE Cur1;
DEALLOCATE Cur1;
GO
Explanation: The table TablesContainer contains all table's ID's and table's names. I just want to print all those table names which I have passed their table ID's to the stored procedure.
The procedure working fine if I pass single value to the variable #TableIDs. But If I pass multiple values like 1,2,3 to #TableIDs then its not getting entered into the cursor.
i think you don't need cursor, there is multiple way to separate string you can pass table value parameter and split the string but as per the Q requirement Reference
DECLARE #temp TABLE (Id INT)
INSERT INTO #temp VALUES (1),(2),(6)
DECLARE #TableIDs varchar(max),
#xml xml
SELECT #TableIDs = '1,2,3,4,5'
SELECT #xml = CONVERT(xml,' <root> <x>' + REPLACE(#TableIDs,',','</x> <x>') + '</x> </root> ')
SELECT id FROM #temp
WHERE id IN (
SELECT T.c.value('.','INT')
FROM #xml.nodes('/root/x') T(c)
)
You don't neet to pass the IDs as a CSV list. SQL Server has table-valued parameters since the SQL Server 2008 version at least. A TVP is a table parameter to which you insert data with plain INSERT statements in SQL, or as an collection (a DataTable or DataReader) in ADO.NET.
You can JOIN with the TVP as you would with any table or table variable.
First, you need to define the TVP type in the database:
CREATE TYPE IdTableType AS TABLE ( ID uniqueidentifier);
Then you can write a stored procedure to use it:
create procedure spGetAllTables(#TableIDs IdTableType READONLY)
AS
SELECT TableName
FROM TablesContainer
inner join #TableIDs on #TableIDs.ID=TablesContainer.TableID
To call the stored procedure from T-SQL you can create a table parameter and fill it:
declare #tableIds IdTableType;
insert into #tableIds
VALUES
('....'),
('....');
exec #spGetAllTables(#tableIds);

SQL Query Delete rows from a table

I have a table #temp. The data in #temp are table names in a database. I wish to only show the table names of which the table has data. How can I do this without using dynamic SQL?
My sample data is as below:
create TABLE #temp (Table_Name VARCHAR(50))
insert into #temp values ('#temp1')
,('#temp2')
,('#temp3')
,('#temp4')
create TABLE #temp1 (Col1 int)
insert into #temp1 values (1)
,(3)
,(4)
create TABLE #temp2 (Col1 int)
insert into #temp2 values (7)
,(9)
,(6)
create TABLE #temp3 (Col1 int)
create TABLE #temp4 (Col1 int)
I manually delete the blank tables, How to do this using a query for numerous blank tables?
DELETE FROM #temp
WHERE Table_Name = '#temp3'
or Table_Name = '#temp4'
This is the result I want
select * from #temp
-- It only shows the two table names which are not blank
DROP TABLE #temp
DROP TABLE #temp1
DROP TABLE #temp2
DROP TABLE #temp3
DROP TABLE #temp4
This is my old query for this question:
DECLARE #TABLE_NAME VARCHAR(50), #COMMAND VARCHAR(500), #COUNT INT, #COUNTT INT
DECLARE #CountResults TABLE (CountReturned INT)
create TABLE #TABLE_NAME (TABLE_NAME VARCHAR(50))
SELECT #COUNTT= COUNT(*) FROM #temp
WHILE #COUNTT > 0
BEGIN
SELECT TOP 1 #TABLE_NAME = Table_Name FROM #temp
SET #COMMAND = 'SELECT COUNT(*) FROM ' + #TABLE_NAME
INSERT #CountResults EXEC (#COMMAND)
SET #Count = (SELECT * FROM #CountResults)
BEGIN TRANSACTION
DELETE #CountResults
ROLLBACK TRANSACTION
IF(#Count > 0)
BEGIN
INSERT INTO #TABLE_NAME VALUES (#TABLE_NAME)
END
DELETE FROM #temp WHERE Table_Name = #TABLE_NAME
SELECT #COUNTT= COUNT(*) FROM #temp
END
SELECT * FROM #TABLE_NAME
I don't know of any way to determine whether or not a table is empty without querying that table, which in your case means dynamic SQL. Your comments make it sound like you're okay with this but are looking for a way to do this more concisely than using a loop. Here's a (limited) possibility:
declare #sql nvarchar(max);
select #sql =
-- coalesce() ensures that UNION ALL is inserted before every SELECT but the first.
coalesce(#sql + N' union all ', N'') +
-- Select each table name. Note that SQL Server allows table names that contain
-- single quotes. In this case (or in the case of plain old bad/malicious data in
-- #temp), we need to make sure those characters are enclosed within the string
-- literal we're building.
N'select ''' + replace(table_name, N'''', N'''''') +
-- Use EXISTS to make sure there are one or more records in the table.
N''' where exists (select 1 from ' + quotename(table_name) + N')'
from #temp;
exec sp_executesql #sql;
This will build and execute a query that looks like this:
select '#temp1' where exists (select 1 from [#temp1])
union all
select '#temp2' where exists (select 1 from [#temp2])
union all
select '#temp3' where exists (select 1 from [#temp3])
union all
select '#temp4' where exists (select 1 from [#temp4])
This approach has a few limitations that you should be aware of:
The query will fail if #temp contains any string which is not the name of a table or view. Normally I'd suggest mitigating this by using object_id() or querying INFORMATION_SCHEMA.TABLES, but the fact that you've loaded #temp with the names of other temp tables complicates matters.
The query will also fail if #temp contains a table name that explicitly names the table schema, e.g. dbo.Stuff, because quotename() will render it as [dbo.Stuff] rather than [dbo].[Stuff]. But if you omit quotename(), you run the risk of incorrect and/or damaging behavior if a table_name contains spaces or other problematic characters.
In short, if you just want something for personal use and are okay with making certain assumptions about the data in #temp, then something like the above ought to work. But if you want something that will work correctly and safely under any circumstances, then it's going to take some doing, enough so that even if you could avoid using some kind of a loop, doing so is unlikely to make things any less complicated.
I have a method that does not use dynamic sql. It uses the sysindexes table, which according to Microsoft is subject to change at their whim. So this may not be a good candidate for a production system. But it could be a good place to start. This is also a bit easier if your source table is not a temp table, since temp tables have actual names that do not match the name used to create them.
This script worked for me on SQL Server 2008 r2.
-- drop table #MyTempTable;
Create table #MyTempTable(Table_Name varchar(50));
insert #MyTempTable values ('#MyTempTable2');
insert #MyTempTable values ('#MyTempTable3');
insert #MyTempTable values ('#MyTempTable4');
Create table #MyTempTable2 (Col1 int);
insert #MyTempTable2 values (1);
Create table #MyTempTable4 (Col1 int);
Create table #MyTempTable3 (Col1 int);
SELECT *
FROM #MyTempTable M1
JOIN tempdb.sys.tables T ON T.name LIKE (M1.Table_Name + '%')
JOIN [tempdb].[dbo].[sysindexes] S ON S.id = T.object_id
WHERE S.rowcnt > 0
It's not an ideal solution, but it satisfies your requirements. If you play around with it in your environment, it might give you some insight into a better way to achieve your larger goals. good luck.
EDIT: sysindexes will have one entry per index on the table. Or in the case of my example, for the heap (with no index.) So if your base tables have multiple indexes, you will need to modify the query a bit. Maybe change the JOIN and WHERE clause to a WHERE EXISTS SELECT * FROM [tempdb].[dbo].[sysindexes] S WHERE S.id = T.object_id AND S.rowcnt > 0 Play with it and you should be able to get where you were asking.
EDIT 2: Replacing sys.tables with sysobjects.
SELECT *
FROM #MyTempTable M1
JOIN [tempdb].[dbo].[sysobjects] O ON O.name LIKE (M1.Table_Name + '%')
JOIN [tempdb].[dbo].[sysindexes] S ON S.id = O.id
WHERE S.rowcnt > 0
Based on DeadZone's Query, the following works for non temp tables:
SELECT DISTINCT Table_Name
INTO #TABLE_NAME
FROM #Temp M1
JOIN [dbo].[sysobjects] O ON O.name LIKE (M1.Table_Name + '%')
JOIN [dbo].[sysindexes] S ON S.id = O.id
WHERE S.rowcnt > 0

Resources