How do I declare strings of data - sql

I have a long code that is creating financial accounting data.
The code uses multiple unions to breakout data to different company groupings.
There are 5-6 account groupings that are reference multiple times.
Anytime there is a change to the groupings I have to go through the code and change it in each location.
An example of the string is below:
Where account in ('81000', '82000','87000','83600','67000')
and account like '814%'
Is there anyway to put this in a declare or just internally link to that code in other where statements?

There are several ways to do what you describe, which is best will depend on your exact needs.
First and simplest is to use variables.
declare #account1 int; set #account1 = 81000;
declare #account2 int; set #account2 = 82000;
declare #account3 int; set #account3 = 87000; /* and so forth*/
It's not clear from your question whether this is being called from a front end app, if it is, you can use sql parameters to set the account values.
string cmd =' declare #account1 int; set #account1 = #acount1In;
select columnslist from accounts where account in (#account1)
union
select columnslist from accounts where account in (#account1)
';
Secondly, you could put the values either into a temporary table or table variable.
declare #accountIds table (account int);
insert into #accountIds values(81000);
select columnlist from accounts where account in (select account from #accounts);
Finally, if this is really the same expression done multiple times, you might consider using a common table expression.
;using cte as (select columnlist from accounts where account in (81000, 87000)
)
select columnlist from cte inner join table2 on a=b
union
select columnlist from cte inner join table3 on a=c

Related

Explain syntax: select #au_id = au_id from #mytemp (Equals sign in SELECT clause) [duplicate]

What are the differences between the SET and SELECT statements when assigning variables in T-SQL?
Quote, which summarizes from this article:
SET is the ANSI standard for variable assignment, SELECT is not.
SET can only assign one variable at a time, SELECT can make multiple assignments at once.
If assigning from a query, SET can only assign a scalar value. If the query returns multiple values/rows then SET will raise an error. SELECT will assign one of the values to the variable and hide the fact that multiple values were returned (so you'd likely never know why something was going wrong elsewhere - have fun troubleshooting that one)
When assigning from a query if there is no value returned then SET will assign NULL, where SELECT will not make the assignment at all (so the variable will not be changed from its previous value)
As far as speed differences - there are no direct differences between SET and SELECT. However SELECT's ability to make multiple assignments in one shot does give it a slight speed advantage over SET.
I believe SET is ANSI standard whereas the SELECT is not. Also note the different behavior of SET vs. SELECT in the example below when a value is not found.
declare #var varchar(20)
set #var = 'Joe'
set #var = (select name from master.sys.tables where name = 'qwerty')
select #var /* #var is now NULL */
set #var = 'Joe'
select #var = name from master.sys.tables where name = 'qwerty'
select #var /* #var is still equal to 'Joe' */
When writing queries, this difference should be kept in mind :
DECLARE #A INT = 2
SELECT #A = TBL.A
FROM ( SELECT 1 A ) TBL
WHERE 1 = 2
SELECT #A
/* #A is 2*/
---------------------------------------------------------------
DECLARE #A INT = 2
SET #A = (
SELECT TBL.A
FROM ( SELECT 1 A) TBL
WHERE 1 = 2
)
SELECT #A
/* #A is null*/
Aside from the one being ANSI and speed etc., there is a very important difference that always matters to me; more than ANSI and speed. The number of bugs I have fixed due to this important overlook is large. I look for this during code reviews all the time.
-- Arrange
create table Employee (EmployeeId int);
insert into dbo.Employee values (1);
insert into dbo.Employee values (2);
insert into dbo.Employee values (3);
-- Act
declare #employeeId int;
select #employeeId = e.EmployeeId from dbo.Employee e;
-- Assert
-- This will print 3, the last EmployeeId from the query (an arbitrary value)
-- Almost always, this is not what the developer was intending.
print #employeeId;
Almost always, that is not what the developer is intending. In the above, the query is straight forward but I have seen queries that are quite complex and figuring out whether it will return a single value or not, is not trivial. The query is often more complex than this and by chance it has been returning single value. During developer testing all is fine. But this is like a ticking bomb and will cause issues when the query returns multiple results. Why? Because it will simply assign the last value to the variable.
Now let's try the same thing with SET:
-- Act
set #employeeId = (select e.EmployeeId from dbo.Employee e);
You will receive an error:
Subquery returned more than 1 value. This is not permitted when the subquery follows =, !=, <, <= , >, >= or when the subquery is used as an expression.
That is amazing and very important because why would you want to assign some trivial "last item in result" to the #employeeId. With select you will never get any error and you will spend minutes, hours debugging.
Perhaps, you are looking for a single Id and SET will force you to fix your query. Thus you may do something like:
-- Act
-- Notice the where clause
set #employeeId = (select e.EmployeeId from dbo.Employee e where e.EmployeeId = 1);
print #employeeId;
Cleanup
drop table Employee;
In conclusion, use:
SET: When you want to assign a single value to a variable and your variable is for a single value.
SELECT: When you want to assign multiple values to a variable. The variable may be a table, temp table or table variable etc.
Surround everything in select with ().
Make sure you are only returning 1 item
eg
ET #sql_update = (select left(#sql_update, len(#sql_update)-1))
SET #Telephone2 = (SELECT REPLACE(LTRIM(REPLACE(#Telephone2, '0', ' ')), ' ', '0'))

sql issue with declare query

I've got a java application that I'm using to retrieve information from a table in sql.
The problem is that the tables change depending on the main application that is using them; there is a view that has all of the active information from the active table eg table_all which is fine, what i want to do is search for a particular number in table that was a part of the view
DECLARE #iss int, #act_tb char(1)
SET #iss = (select cust_nr from table_all where num = '123456789')
SET #act_tb = (select curr_table_active from pc_group where cust_nr = #iss)
select * from pc_grp_#iss_#act_tb
so what i would now want to do is update a field in pc_grp_#iss_#act_tbenter code here format is pc_grp_<#iss>_<#act_tb>.
is there any way i can do that as pc_grp_#iss_#act_tb is picked up as a table and not a variable table name.
Many thanks
i think you are looking for this-:
Declare #query as varchar(Max);
Set #query='Select * from select * from pc_grp_'+Cast(#iss as varchar)+'_'+Cast(#act_tb as varchar) ;
Exec(#query)

Dynamically Select from different DB's based on input to sproc

I'm trying to alter a stored procedure in our DB from a hard-coded select from 1 specific DB to be able to select from any of our DB's based on an id that's passed into the sproc. Here's the stub of what the sproc is doing for us:
ALTER PROCEDURE [dbo].[GetByAdId]
(
#AdId int,
#UserCompanyId int
)
AS
SET NOCOUNT ON
SELECT
[User].[UserId],
UserMappings.IsActive,
IsAccountOwner = ( SELECT Count(*) FROM DB1_SetUp.dbo.ad Adv WHERE Adv.AdID = UserMappings.AdID AND Adv.PrimaryAccountOwnerID = [User].[UserId] )
FROM
[User] INNER JOIN UserMappings ON
(
UserMappings.UserID = [User].UserID
AND UserMappings.AdID = #AdId
AND UserMappings.UserCompanyId = #UserCompanyId
)
Basically the "IsAccountOwner" variable is hardcoded to select from DB1_SetUp every time, but we have a number of SetUp db's for different groups, so like DB2_SetUp, DB3_SetUp, etc. The UserCompanyId variable being passed into the sproc functions like a group Id and can be used to point to the particular SetUp DB I want it to select from, but I'm not sure how to do this. I basically wanted something on the ilk of:
SELECT * FROM (
CASE #UserCompanyId
WHEN 3 THEN 'DB3_SetUp'
WHEN 4 THEN 'DB4_SetUp'
)
Is there a clean way to do this, or will I have to setup this sproc on each group DB and call the specific one over on each DB?
I've done this in the past by dynamically building the SQL I wanted to execute (based on parameters passed in) and then executing the SQL using sp_executesql
see: http://msdn.microsoft.com/en-us/library/ms188001.aspx

How can one iterate over stored procedure results from within another stored procedure....without cursors?

I'm not sure if this is something I should do in T-SQL or not, and I'm pretty sure using the word 'iterate' was wrong in this context, since you should never iterate anything in sql. It should be a set based operation, correct? Anyway, here's the scenario:
I have a stored proc that returns many uniqueidentifiers (single column results). These ids are the primary keys of records in a another table. I need to set a flag on all the corresponding records in that table.
How do I do this without the use of cursors? Should be an easy one for you sql gurus!
This may not be the most efficient, but I would create a temp table to hold the results of the stored proc and then use that in a join against the target table. For example:
CREATE TABLE #t (uniqueid int)
INSERT INTO #t EXEC p_YourStoredProc
UPDATE TargetTable
SET a.FlagColumn = 1
FROM TargetTable a JOIN #t b
ON a.uniqueid = b.uniqueid
DROP TABLE #t
You could also change your stored proc to a user-defined function that returns a table with your uniqueidentifiers. You can joing directly to the UDF and treat it like a table which avoids having to create the extra temp table explicitly. Also, you can pass parameters into the function as you're calling it, making this a very flexible solution.
CREATE FUNCTION dbo.udfGetUniqueIDs
()
RETURNS TABLE
AS
RETURN
(
SELECT uniqueid FROM dbo.SomeWhere
)
GO
UPDATE dbo.TargetTable
SET a.FlagColumn = 1
FROM dbo.TargetTable a INNER JOIN dbo.udfGetUniqueIDs() b
ON a.uniqueid = b.uniqueid
Edit:
This will work on SQL Server 2000 and up...
Insert the results of the stored proc into a temporary table and join this to the table you want to update:
INSERT INTO #WorkTable
EXEC usp_WorkResults
UPDATE DataTable
SET Flag = Whatever
FROM DataTable
INNER JOIN #WorkTable
ON DataTable.Ket = #WorkTable.Key
If you upgrade to SQL 2008 then you can pass table parameters I believe. Otherwise, you're stuck with a global temporary table or creating a permanent table that includes a column for some sort of process ID to identify which call to the stored procedure is relevant.
How much room do you have in changing the stored procedure that generates the IDs? You could add code in there to handle it or have a parameter that lets you optionally flag the rows when it is called.
Use temporary tables or a table variable (you are using SS2005).
Although, that's not nest-able - if a stored proc uses that method then you can't dumpt that output into a temp table.
An ugly solution would be to have your procedure return the "next" id each time it is called by using the other table (or some flag on the existing table) to filter out the rows that it has already returned
You can use a temp table or table variable with an additional column:
DECLARE #MyTable TABLE (
Column1 uniqueidentifer,
...,
Checked bit
)
INSERT INTO #MyTable
SELECT [...], 0 FROM MyTable WHERE [...]
DECLARE #Continue bit
SET #Continue = 1
WHILE (#Continue)
BEGIN
SELECT #var1 = Column1,
#var2 = Column2,
...
FROM #MyTable
WHERE Checked = 1
IF #var1 IS NULL
SET #Continue = 0
ELSE
BEGIN
...
UPDATE #MyTable SET Checked = 1 WHERE Column1 = #var1
END
END
Edit: Actually, in your situation a join will be better; the code above is a cursorless iteration, which is overkill for your situation.

Implement symmetric difference in SQL Server?

Here's a problem I've been trying to solve at work. I'm not a database expert, so that perhaps this is a bit sophomoric. All apologies.
I have a given database D, which has been duplicated on another machine (in a perhaps dubious manner), resulting in database D'. It is my task to check that database D and D' are in fact exactly identical.
The problem, of course, is what to actually do if they are not. For this purpose, my thought was to run a symmetric difference on each corresponding table and see the differences.
There is a "large" number of tables, so I do not wish to run each symmetric difference by hand. How do I then implement a symmetric difference "function" (or stored procedure, or whatever you'd like) that can run on arbitrary tables without having to explicitly enumerate the columns?
This is running on Windows, and your hedge fund will explode if you don't follow through. Good luck.
Here is the solution. The example data is from the ReportServer database that comes with SSRS 2008 R2, but you can use it on any dataset:
SELECT s.name, s.type
FROM
(
SELECT s1.name, s1.type
FROM syscolumns s1
WHERE object_name(s1.id) = 'executionlog2'
UNION ALL
SELECT s2.name, s2.type
FROM syscolumns s2
WHERE object_name(s2.id) = 'executionlog3'
) AS s
GROUP BY s.name, s.type
HAVING COUNT(s.name) = 1
You can achieve this by doing something like this.
I have used a function to split comma separated value into a table to demostrate.
CREATE FUNCTION [dbo].[Split]
(
#RowData nvarchar(2000),
#SplitOn nvarchar(5)
)
RETURNS #RtnValue table
(
Id int identity(1,1),
Data nvarchar(100)
)
AS
BEGIN
Declare #Cnt int
Set #Cnt = 1
While (Charindex(#SplitOn,#RowData)>0)
Begin
Insert Into #RtnValue (data)
Select
Data = ltrim(rtrim(Substring(#RowData,1,Charindex(#SplitOn,#RowData)-1)))
Set #RowData = Substring(#RowData,Charindex(#SplitOn,#RowData)+1,len(#RowData))
Set #Cnt = #Cnt + 1
End
Insert Into #RtnValue (data)
Select Data = ltrim(rtrim(#RowData))
Return
END
GO
DECLARE #WB_LIST varchar(1024) = '123,125,764,256,157';
DECLARE #WB_LIST_IN_DB varchar(1024) = '123,125,795,256,157,789';
DECLARE #TABLE_UPDATE_LIST_IN_DB TABLE ( id varchar(20));
DECLARE #TABLE_UPDATE_LIST TABLE ( id varchar(20));
INSERT INTO #TABLE_UPDATE_LIST
SELECT data FROM dbo.Split(#WB_LIST,',');
INSERT INTO #TABLE_UPDATE_LIST_IN_DB
SELECT data FROM dbo.Split(#LIST_IN_DB,',');
SELECT * FROM #TABLE_UPDATE_LIST
EXCEPT
SELECT * FROM #TABLE_UPDATE_LIST_IN_DB
UNION
SELECT * FROM #TABLE_UPDATE_LIST_IN_DB
EXCEPT
SELECT * FROM #TABLE_UPDATE_LIST;
My first reaction is to suggest duplicating to the other machine again in a non-dubious manner.
If that is not an option, perhaps some of the tools available from Red Gate could do what you need.
(I am in no way affliated with Red Gate, just remember Joel mentioning how good their tools were on the podcast.)
SQL Server 2000 Added the "EXCEPT" keyword, which is almost exactly the same as Oracle's "minus"
SELECT * FROM TBL_A WHERE ...
EXCEPT
SELECT * FROM TBL_B WHERE ...
Use the SQL Compare tools by Red Gate. It compares scheamas, and the SQL Data Compare tool compares data. I think that you can get a free trial for them, but you might as well buy them if this is a recurring problem. There may be open source or free tools like this, but you might as well just get this one.