Select UNION from multiple tables via variable - sql-server-2008

I have a query that selects from multiple tables using a join. I want to execute this query from different databases via a loop.
I have accomplished that via (simplified query):
DECLARE #intCounter int
SET #intCounter = 1
DECLARE #tblBedrijven TABLE (ID int identity(1,1),
CompanyName varchar(20),
DatabaseTable varchar(100))
INSERT INTO #tblBedrijven VALUES ('001-CureCare', '<TABLE/ DATABASE1> AUS'),
('002-Cleaning', '[global_nav5_prod].[dbo].<TABLE/ DATABASE2>] AUS')
DECLARE #strCompany varchar(20)
DECLARE #strTable varchar(100)
WHILE (#intCounter <= (SELECT MAX(ID) FROM #tblBedrijven))
BEGIN
SET #strTable = (SELECT DatabaseTable FROM #tblBedrijven
WHERE ID = #intCounter)
SET #strCompany = (SELECT CompanyName FROM #tblBedrijven
WHERE ID = #intCounter)
EXEC('SELECT ''' + #strCompany + ''' as Company,
AUS.[User],
AUS.[E-mail]
FROM' + #strTable)
SET #intCounter = #intCounter + 1
END
My problem is that the result generates 2 separate tables (for every loop). I want to union the results but have no clue how.
Any suggestions?
Thanks in advance.

Can't you use something like the below code where you append all the sqls with union and finally execute the sql once only without executing in a loop. I am not an expert in SQL Server but I have written many other similar stored procedures using other RDBMS. So please bear any syntax errors.
DECLARE #intCounter int
DECLARE #maxId int
SET #intCounter = 1
DECLARE #tblBedrijven TABLE (ID int identity(1,1),
CompanyName varchar(20),
DatabaseTable varchar(100))
INSERT INTO #tblBedrijven VALUES ('001-CureCare', '<TABLE/ DATABASE1> AUS'),
('002-Cleaning', '[global_nav5_prod].[dbo].<TABLE/ DATABASE2>] AUS')
DECLARE #strCompany varchar(20)
DECLARE #strTable varchar(100)
DECLARE #strSql varchar(5000)
SET #maxId = (SELECT MAX(ID) FROM #tblBedrijven)
WHILE (#intCounter <= #maxId)
BEGIN
SET #strTable = (SELECT DatabaseTable FROM #tblBedrijven
WHERE ID = #intCounter)
SET #strCompany = (SELECT CompanyName FROM #tblBedrijven
WHERE ID = #intCounter)
SET #strSql = #strSql + ('SELECT ''' + #strCompany + ''' as Company,
AUS.[User],
AUS.[E-mail]
FROM' + #strTable)
IF #intCounter < #maxId THEN
BEGIN
SET #strSql = #strSql + ' UNION '
END
SET #intCounter = #intCounter + 1
END
EXEC(#strSql)

Related

Visual Studio 2010 Reporting Services - how to populate something when nothing is returned

I'm using a query with two parameters (#campaign,#resultcode) to populate a table with 3 columns ("Campaignname","Disposition","Count"), but when either one of those parameters don't exist in the database, nothing populates in the table. Is there a way to make it populate the two parameters with a count of 0? Also I have it set so that multiple parameters can be selected. I've tried IIF(IsNothing()..., IIF(***.value = null or ""). Still doesn't do what I want it to do. Some help?
Included code from comment response:
SELECT databasename, callresultdescription, count(*) as Count
FROM bpsql00.[histCallCenterStats].[dbo].[CallResults]
WHERE databasename IN(#campaign) AND callresultcode IN(#resultcode)
GROUP BY databasename, callresultdescription
The callresultdescription is AKA disposition
You could union them together:
--create table [CallResults] (databasename varchar(10),callresultdescription
varchar(10),myvalue int)
--insert into [CallResults]
--values ('a','AA',1),
--('b','BB',2),
--('c','CC',3)
--select * from [CallResults]
declare #campaign varchar(10)='d',#resultcode varchar(10)='dd' ;
SELECT databasename, callresultdescription,
count(1) as [Count]
FROM [CallResults]
WHERE databasename IN (#campaign)
AND callresultdescription IN (#resultcode)
GROUP BY databasename, callresultdescription
UNION
SELECT databasename=#campaign,
callresultdescription=#resultcode,
0 as [Count]
from [CallResults]
where databasename not IN (#campaign)
AND callresultdescription not IN (#resultcode)
You can accomplish this with an IF statement in the SQL query:
IF EXISTS (SELECT 1 FROM bpsql00.[histCallCenterStats].[dbo].[CallResults] WHERE databasename IN ( #campaign ) AND callresultcode IN ( #resultcode ))
SELECT databasename
, callresultdescription
, [Count] = COUNT(*)
FROM bpsql00.[histCallCenterStats].[dbo].[CallResults]
WHERE databasename IN ( #campaign )
AND callresultcode IN ( #resultcode )
GROUP BY databasename ,
callresultdescription;
ELSE
SELECT databasename = #campaign
, callresultdescription = #resultcode
, [Count] = 0
Edit per question in the comment:
It gets tricky when you need to return a multi-valued parameter. If you're on SQL 2016, you can use the new TSQL STRING_SPLIT function to split out their comma-separated selections. There are also splitter functions you can find on the interwebs for prior versions of SQL. The simplest solution, though, is to let the query return nothing and set the NoRowsMessage of the tablix to inform the client. You can use an expression like
="No records found in the selected campaigns (" & _
Parameters!campaign.Value & ") and result codes (" & _
Parameters!resultcode.Value & ")."
That gives the user a record of what was searched and that nothing was found to match their criteria.
So finally figured it out. I have concluded that the program is limited what I wanted to do. So... why not let SQL do it for me and I can just call a stored procedure. BINGO. I had to create a function as well. So for anyone who needs something like this.
Stored procedure I created:
alter procedure [dbo].[rs_Query]
#campaign varchar (100),
#resultcode varchar (100)
as
Begin
declare #var_campaign varchar(100)
declare #var_resultcode varchar(100)
declare #c table(ID int identity, databasename varchar(100))
declare #r table(ID int identity, callresultcode varchar(100))
insert into #c select element from dbo.func_split(#campaign, ',')
insert into #r select element from dbo.func_split(#resultcode,',')
declare #dbcnt int --count of campaigns selected
declare #crcnt int --count of dispositions selected
declare #crrow int --row id for campaigns selected
declare #dbrow int --row id for dispositions selected
declare #tempdbname varchar(50) --temp campaign name
declare #tempcr varchar(50) --temp call result name
declare #t table (databasename varchar(100), callresultdescription varchar (100), Count int)
declare #count int
select #dbcnt = count(*) from #c
select #crcnt = count(*) from #r
select #dbrow = 1
select #crrow = 1
while #dbcnt >= #dbrow
begin
set #tempdbname = (select databasename
from bpsql00.callcenteraux.dbo.DailyReportsCampaign
where databasename = (select databasename from #c where id = #dbrow))
set #crrow = 1
while #crcnt >= #crrow
begin
set #tempcr = (select CallResultDescription
from CallResultCode
where CallResultCode = (select CallResultCode from #r where id = #crrow));
if exists(select 1 from bpsql00.[histCallCenterStats].[dbo].[CallResults]
where CallResultCode = (select CallResultCode from #r where id = #crrow) and databasename = #tempdbname)
begin
select #count = count(*) from bpsql00.[histCallCenterStats].[dbo].[CallResults]
where CallResultCode = (select CallResultCode from #r where id = #crrow) and databasename = #tempdbname
insert into #t values(#tempdbname,#tempcr,#count)
end
else
begin
insert into #t values(#tempdbname,#tempcr,0)
end
set #crrow = #crrow + 1
end
set #dbrow = #dbrow + 1
end
select * from #t
end
And function I created:
ALTER FUNCTION [dbo].[func_Split]
(
#DelimitedString varchar(8000),
#Delimiter varchar(100)
)
RETURNS #tblArray TABLE
(
ElementID int IDENTITY(1,1), -- Array index
Element varchar(1000) -- Array element contents
)
AS
BEGIN
-- Local Variable Declarations
-- ---------------------------
DECLARE #Index smallint,
#Start smallint,
#DelSize smallint
SET #DelSize = LEN(#Delimiter + 'x') - 1
-- Loop through source string and add elements to destination table array
-- ----------------------------------------------------------------------
WHILE LEN(#DelimitedString) > 0
BEGIN
SET #Index = CHARINDEX(#Delimiter, #DelimitedString)
IF #Index = 0
BEGIN
INSERT INTO
#tblArray
(Element)
VALUES
(LTRIM(RTRIM(#DelimitedString)))
BREAK
END
ELSE
BEGIN
INSERT INTO
#tblArray
(Element)
VALUES
(LTRIM(RTRIM(SUBSTRING(#DelimitedString, 1,#Index - 1))))
SET #Start = #Index + #DelSize
SET #DelimitedString = SUBSTRING(#DelimitedString, #Start , LEN(#DelimitedString) - #Start + 1)
END
END
RETURN
END

When I am trying to drop tables using below script , it seems not working.

I am trying to drop tables from each server. My Server 1 has 3 Databases and Server 2 has 6 and Server 3 has 8.
Below is the SQL Script that I wrote to perform the drop operation from each databases in in particular server. After I perform these operation.
DECLARE
#LoopId int,
#Command varchar(500),
#tblName varchar(100)
DECLARE #List TABLE
(
TableName sysname not null,
LoopId int not null identity(1,1)
)
-- Load with tables you wish to drop
INSERT #List (TableName)
SELECT name FROM [Morgage].sys.objects WHERE type = 'u' and name like '%JKL%'
SELECT name FROM [Scorecard].sys.objects WHERE type = 'u'and name like '%JKL%'
SELECT name FROM [Core].sys.objects WHERE type = 'u' and name like '%JKL%'
SET #LoopId = ##rowcount
-- Go through list and process each item
WHILE #LoopId > 0
BEGIN
SET #tblName = (SELECT TableName from #List where LoopId = #LoopId)
SET #Command = 'Drop table ' + #tblName
execute (#Command)
SET #LoopId = #LoopId - 1
END
Above query result says rows affected but then when i go and try to test is using below query. I do see everything. What my query did actually? Am I doing it right?
SELECT name FROM [Scorecard].sys.objects WHERE type = 'u'and name like '%JKL%'
Any help will be appreciated. Thanks.
Try this version of your script:-
DECLARE
#LoopId int,
#Command varchar(500),
#tblName varchar(100),
#dbName sysname
DECLARE #List TABLE
(
DBName sysname not null,
TableName sysname not null,
LoopId int not null identity(1,1)
)
-- Load with tables you wish to drop
INSERT #List (DBName, TableName)
SELECT 'Morgage',name FROM [Morgage].sys.objects WHERE type = 'u' and name like '%JKL%'
UNION
SELECT 'Scorecard',name FROM [Scorecard].sys.objects WHERE type = 'u'and name like '%JKL%'
UNION
SELECT 'Core',name FROM [Core].sys.objects WHERE type = 'u' and name like '%JKL%'
SET #LoopId = ##rowcount
-- Go through list and process each item
WHILE #LoopId > 0
BEGIN
SELECT #tblName = TableName, #dbName=DBName from #List where LoopId = #LoopId
SET #Command = 'USE ' + #dbName + ';if not exists(select 1 from sys.foreign_keys where parent_object_id=object_id(''' + #tblName + ''',''U'')' + char(10) + 'Drop table ' + #tblName + ';'
execute (#Command)
SET #LoopId = #LoopId - 1
END
Might be the queries are not committing by default. Try specify it explicitly

List tables, type of access a specific database user has

I am trying to get a list of all the tables and the rights on them for a specific user at database level, e.g.:
User Name DBName TableName Type of Access
========= ====== ========= ==============
... ... ... ...
I have tried using...
EXEC sp_helprolemember
EXEC sp_helprotect
...and others, but they did not really help me.
I also tried using sp_msloginmappings but this failed as I do not have admin rights on the server.
Please suggest me some pointers or examples.
I'm not an expert in T-SQL but, this might do what you want hopefully.
declare #Proc nvarchar(50)
declare #RowCnt int
declare #MaxRows int
declare #ExecSql nvarchar(255)
select #RowCnt = 1
select #Proc = 'SELECT * from fn_my_permissions'
declare #Import table (rownum int IDENTITY (1, 1) Primary key NOT NULL , TableName varchar(50))
insert into #Import (TableName) select name from sys.Tables
declare #Output table (entity_name varchar(50), subentity_name varchar(50), permission_name varchar(50))
select #MaxRows=count(*) from #Import
while #RowCnt <= #MaxRows
begin
select #ExecSql = #Proc + '(N''' + TableName + ''', N''OBJECT'') where subentity_name = ''''' from #Import where rownum = #RowCnt
insert into #Output exec sp_executesql #ExecSql
Select #RowCnt = #RowCnt + 1
end
select * from #Output
This will give the Permissions for the current user. If you want to find the permissions for a given user then try the following;
EXECUTE AS LOGIN = N'username'
GO
declare #Proc nvarchar(50)
declare #RowCnt int
declare #MaxRows int
declare #ExecSql nvarchar(255)
select #RowCnt = 1
select #Proc = 'SELECT * from fn_my_permissions'
declare #Import table (rownum int IDENTITY (1, 1) Primary key NOT NULL , TableName varchar(50))
insert into #Import (TableName) select name from sys.Tables
declare #Output table (entity_name varchar(50), subentity_name varchar(50), permission_name varchar(50))
select #MaxRows=count(*) from #Import
while #RowCnt <= #MaxRows
begin
select #ExecSql = #Proc + '(N''' + TableName + ''', N''OBJECT'') where subentity_name = ''''' from #Import where rownum = #RowCnt
insert into #Output exec sp_executesql #ExecSql
Select #RowCnt = #RowCnt + 1
end
select * from #Output
GO
REVERT
GO
Of course, just replace username with the login of the user you need to get the permissions for.
You'll also have to specify which database you want to execute this for.
I've restricted the results to the table itself. However, if you remove the;
where subentity_name = '''''
You can find the Permissions for each Column aswell.
I'm sure there must be a better way of doing this... But, this seems to work anyhow!
This has worked for me in the past, tells me what they have access to and what kind of access
select princ.name
, princ.type_desc
, perm.permission_name
, perm.state_desc
, perm.class_desc
, object_name(perm.major_id)
from sys.database_principals princ
left join
sys.database_permissions perm
on perm.grantee_principal_id = princ.principal_id
WHERE princ.name = 'USERNAME'

How can I insert values into table like Bulk Insert?

I have values like
string a,b;
a= "1,2,3,4";
b="admin";
I am passing a and b to SP and I want to save it in DB like
a b
1 admin
2 admin
3 admin
4 admin
How can I do this? Can someone give me some ideas on how to do it?
Thank you..
SQL doesn't have a concept of arrays, so this gets a bit interesting.
Pass a list as a string parameter:
DECLARE #INSTR as VARCHAR(MAX)
SET #INSTR = '2,3,177,'
DECLARE #SEPERATOR as VARCHAR(1)
DECLARE #SP INT
DECLARE #VALUE VARCHAR(1000)
SET #SEPERATOR = ','
WHILE PATINDEX('%' + #SEPERATOR + '%', #INSTR ) <> 0
BEGIN
SELECT #SP = PATINDEX('%' + #SEPERATOR + '%',#INSTR)
SELECT #VALUE = LEFT(#INSTR , #SP - 1)
SELECT #INSTR = STUFF(#INSTR, 1, #SP, '')
INSERT INTO myTable (a, b) VALUES (#VALUE, 'admin')
END

Handling larger strings in Sql Server 2008

We have an stored procedure that we created so that user can write comma separated search tags in their software product's admin. So he can add comma-separated tags and in case if he wants to edit them, we read from the table all the tags, recreate them as comma-separated values (CSV) in stored procedure and returns that to the calling code. What happened recently, the user complained that he could not see the new CSVs he wrote. I looked into it and found out that the stored procedure is truncating the string when it reads values from database and creates CSV string. The string is of type nvarchar, and because its exceeding the max characters of 4000 limit, the values gets truncated. Any ideas on how to work out that problem.
Find my code underneath.
BEGIN
BEGIN
Declare #Synonyms Table
(
RowID int Identity(1,1),
SynonymID int,
[Synonym] nvarchar(4000)
);
SET NOCOUNT ON;
Insert #Synonyms(SynonymID, [Synonym])
Select distinct SynonymID, [Synonym] From RF_SearchSynonyms with(nolock) Where SearchTermID = #SearchTermID And ActiveInd = 1
If((Select COUNT(RowID) From #Synonyms) <> 0)
BEGIN
Declare #CurrentRow int = (Select MIN(RowID) From #Synonyms),
#TotalRows int = (Select MAX(RowID) From #Synonyms),
#Synonyms_CSV nvarchar(4000) = '';
WHILE #CurrentRow <= #TotalRows
BEGIN
Declare #TempSyn nvarchar(500);
Select #TempSyn = [Synonym] + ',' From #Synonyms Where RowID = #CurrentRow;
Set #Synonyms_CSV = #Synonyms_CSV + LTRIM(RTRIM(LOWER(#TempSyn)));
SET #CurrentRow = #CurrentRow + 1
END
END
Else
BEGIN
Set #Synonyms_CSV = '';
END
END
BEGIN
Declare #SKUs Table
(
RowID int Identity(1,1),
SkuID int,
SKU nvarchar(15)
);
SET NOCOUNT ON;
Insert #SKUs(SkuID, SKU)
Select distinct SkuID, SKU From RF_SearchSkus with(nolock) Where SearchTermID = #SearchTermID And ActiveInd = 1
If((Select COUNT(RowID) From #SKUs) <> 0)
BEGIN
Declare #CurrentRow1 int = (Select MIN(RowID) From #SKUs),
#TotalRows1 int = (Select MAX(RowID) From #SKUs),
#Skus_CSV nvarchar(4000) = '';
WHILE #CurrentRow1 <= #TotalRows1
BEGIN
Declare #TempSku nvarchar(15);
Select #TempSku = SKU + ',' From #SKUs Where RowID = #CurrentRow1;
Set #Skus_CSV = #Skus_CSV + LTRIM(RTRIM(#TempSku));
SET #CurrentRow1 = #CurrentRow1 + 1
END
END
Else
BEGIN
Set #Skus_CSV = '';
END
END
BEGIN
Declare #Combined varchar(8000),
#syn_len int = 0,
#sku_len int = 0;
Select #syn_len = LEN(#Synonyms_CSV);
Select #sku_len = LEN(#Skus_CSV);
Select #Combined = #Synonyms_CSV + '-_-' + #Skus_CSV;
Select #Synonyms_CSV + '-_-' + #Skus_CSV;
END
END
I can't use text and ntext as they do not play nice with concatenation operations.
Thanks.
How are your declaring the string parameter?
nvarchar(max)
supports up to 2^32-1 (2GB)
See this link.