I have an odd case where when I look at the data through my SQL scripts I have one value, but if I look at the data directly SELECT * FROM table I get another value.
My first thought was parameter sniffing, but that didn't fix the issue. I'm not doing anything with the value at hand, except getting it with a stored procedure.
Example of the stored procedure.
CREATE PROCEDURE example
(
#iRefProjectID int
)
AS
-- Prevent Parameter sniffing
DECLARE #projectID int
SET #projectID = #iRefProjectID
SELECT iEntryType
FROM table
WHERE iEntryType IN (1,5,6)
AND iProjectID = #projectID
RETURN
GO
Now one of the rows so extracted contains a '2', which when I look at it through the SP it is a '1'. It shouldn't have been picked at all being 2 != 1 || 5 || 6. Suddenly the 2 becomes a 1 and then "1" == 1.
Where should I look to kill this bug.
The rows in question
SELECT * FROM table
3264427 2003-11-25 00:00:00.000 **2** Udligning til afregning F83907 100625.00
Exec SP
3264427 2003-11-25 00:00:00.000 -100625.00 Udligning til afregning F83907 **1**
Ahh .. found something. This rather looks like a Join bug.
There is no such bug.
You probably have 2 tables with same name in different schemas. Example: dbo.table and [DOMAIN\User].table
Best practice is always qualify objects to avoid incorrect schema resolution.
There are other options such as:
different databases
different servers
table is actually an unrefreshed view
dirty read (as per Yves M. comment) because you have changed isolation level
Related
I am still quite new to this but am ready to take the next step. I am trying to execute multiple queries at once, if at all possible. From reading some other questions, it seems as if creating a stored procedure is the best route.
The task at hand is creating 36 reports. In this case, hoping to create all 36 reports at one time and not have the results be one continuous entity. Each uses a query very similar to the code shown below. The query shown below is simply the first report to be created out of 36. The only difference in the 36 is the values in the WHERE statement. I am hoping for an operation or method that keeps me from copying and pasting 36 chunks of code into SQL and then copying and pasting those results into an excel spreadsheet.
So my question is 1. Can this be done? 2. Is a stored procedure the best method for this task?
SELECT
'000000' AS area,
[SizeClass],
COUNT(*) AS [Number of Worksites],
SUM(Employment) AS [Employment In Size Class]
FROM
dbo.sizeclassreport
WHERE
code LIKE '11%' OR code LIKE '21%'
GROUP BY
[SizeClass]
ORDER BY
[SizeClass]
It gets tricky if the 36 reports you are talking about pass a different number of arguments and also if they have wildcards AND also if the WHERE clause involves different columns. I would probably write a sproc with the max. number of parameters a report could pass like this for a max of three:
CREATE PROCEDURE dbo.sp_Test
#code1 varchar(80),
#code2 varchar(80),
#code3 varchar(80)
AS
BEGIN
IF(#code1 is null or #code1 = '')
BEGIN
RAISERROR('bad arguments!',16,1);
RETURN;
END
select
[cols]
from
dbo.tbl
where
([Code] like #code1) OR
(#code2 is NOT null AND [Code] like #code2) OR
(#code3 is NOT null AND [Code] like #code3)
END
Where at least code1 is expected at all times and the rest are optional. if the where clause involves different columns depending on the report, then I suggest you do multiple sprocs with a similar approach as above to accomodate the different searches.
I have been asked to do a bit of work on a SQL Server 2005 query that has 26 (!) nested Replace function calls.
There are two issues with this query.
The first is that the 26 replace functions are not enough, a few more are needed, but the query is hitting some size limitations (it's a stored procedure and its making using of sp_MSforEachDB).
The second problem is that the query is just not legible at this stage.
I would like to use table variable with a lookup, but the issue is that the replace query is being used to replace values in one column with values from another column. It does however all work, apparent from not replacing enough strings.
Here is a simplified example to hopefully better explain what I am trying to do.
Table to be converted
ID MainText Ptext1 Ptext2 Ptext3
1 Have a %Ptxt1 %Ptxt2 Apple Tonight
2 %Ptxt1 likes %Ptxt2 at %Ptxt3 Sally Cake Midnight
The desired result for 1 is "Have a Apple Tonight", the desired result for 2 is "Sally Likes Cake at Midnight".
The current SQL Looks a bit like
EXEC sp_MSForEachDB 'IF ''?'' LIKE ''%Database%''
Select Replace(Replace(Replace([Maintext], '%Ptxt1' , [Ptext1]),'%Ptxt2',[Ptext2]),'Ptxt3', [Ptext3]) from dbo.mytable
Please forgive any mistakes in the example.
I have seen nice examples of people using Table variables to store parameters for the replace function - but I haven't seen any where a column reference is used instead of a static string, is this possible ?
Call your base table: MyData.
Create a new table named MyValues (id, Token, data_value). the ID is FK to you base table. for each record in MyData, insert the values of field names into MyValues.
So, MyValues looks like
Id Token data_value
==== ====== ==========
1 Ptxt1 Apple
1 Ptxt2 Tonight
2 Ptxt1 Sally
2 Ptxt2 Cake
2 Ptxt3 Midnight
and so on...
Then you can join MyTable with MyValues.
Now, one way of solving the problem, is looping on MyData and inner loop on MyValues.
declare #i int
for each value in MyData
begin
#i++
read MyDaya.MainText into #mainText
for each value in MyValues where ID = Id of the MainData
begin
read MyValues.data_value into #actualValue
read MyValues.Token into #token
#mainText = Replace(#mainText, #toekn, #actualValue)
Update MyData with mainText or do what ever appropriate
end
end
This is pseudo-code, I hope you can implement that in T- SQL
I am going round in circles with a bit of SQL and would appreciate some help.
I've looked up creating temp tables, nested Select statements (where advice seems to be to avoid these like the plague) and various uses of Case statements but I can't seem to find a solution that works. I'd say I'm beginner level for SQL.
I have a table with 10 relevant records. The query that works to return all the relevant entries in the table is:
SELECT
TblServAct.ServActId
,TblServAct.ServActName
FROM TblServAct
WHERE TblServAct.ServActExclude IS NULL
ORDER BY TblServAct.ServActName
Here is where I run into problems:
When the parameter (#YESNOActivity) = Yes, I want all the rows in the table to be returned. I have managed to do this with a CASE statement
...however when the parameter (#YESNOActivity) = No, I want ONLY ONE row to be returned which doesn't actually exist in the table (and should not be inserted into the actual table). The values that I need to insert are: ServActId = 101 and ServActName = 'Select YES in Parameter2 to filter by Service Activity'
For background, the reason I am doing this is because I have found SSRS report parameters to be especially difficult to conditionally format. I want to use the dataset above to return a message in a parameter (lets call it parameter2) that the user needs to select yes in (#YESNOActivity) in order to see the full selection list in parameter2.
If I can get this to work I can see lots of potential for re-use so all advice appreciated
Thanks
Eileen
I believe this should do the job, just include your parameter in the WHERE clause and UNION it with your own row of data.
SELECT
TblServAct.ServActId
,TblServAct.ServActName
FROM TblServAct
WHERE TblServAct.ServActExclude IS NULL
AND #YESNOActivity = 'Yes'
UNION ALL
SELECT
ServActId = 101
,ServActName = 'Select YES in Parameter2 to filter by Service Activity'
WHERE #YESNOActivity = 'No'
ORDER BY TblServAct.ServActName
One way is to use this query:
SELECT
TblServAct.ServActId
,TblServAct.ServActName
FROM TblServAct
WHERE TblServAct.ServActExclude IS NULL
AND 'Yes' = #YESNOActivity
UNION ALL
SELECT
101 AS ServActId
,'Select YES in Parameter2 to filter by Service Activity' AS ServActName
WHERE 'No' = #YESNOActivity
ORDER BY TblServAct.ServActName
Another way would be to create two data flows and use your variable in a constraint to send the processing to one or the other.
A third way would be to put an expression on the SQL command and use your variable to switch between two SQL statements.
Everywhere I look I see that in order to loop through results you have to use a cursor and in the same post someone saying cursors are bad don't use them (which has always been my philosophy) but now I am stuck. I need to loop through a result set!
Here's the situation. I need to come up with a list of ProductIDs that have 2 different statuses set to a specific value. I start the stored procedure, run the query that finds my products that meet the criteria.
So, now I have a list of ProductIDs that I need to run through my validation process:
16050
16052
41817
48255
Now I need for each of those products (there may be 1 there may be 1000, i don't know) to check a whole list of conditions:
Is a specific field = 'SIMPLE'? if so, perform a bunch of other queries and make sure everything is good
If it is not 'SIMPLE' then run a whole other set of queries and make sure that information is all good.
Is another field = 'YES'? if so, perform a bunch of other queries, if it is not, then do other queries.
Is a cursor what I need to use? Is there some other way to do what I need that I just am not seeing?
Thanks,
Leslie
I ended up using a WHILE loop that I can pass each ProductID into a series of checks!!
declare #counter int
declare #productKey varchar(20)
SET #counter = (select COUNT(*) from ##Magento)
while (1=1)
begin
SET #productKey = (select top 1 ProductKey from ##Magento)
print #productKey;
delete from ##Magento Where ProductKey = #productKey
SET #counter-=1;
IF (#counter=0) BREAK;
end
go
It's hard to say without knowing the specifics of your process, but one approach is to create a function that performs your logic and call that.
eg:
delete from yourtable
where productid in (select ProductID from FilteredProducts)
and dbo.ShouldBeDeletedFunction(ProductID) = 1
In general, cursors are bad, but there are always exceptions. Try to avoid them by thinking in terms of sets, rather than the attributes of an individual record.
The question from quite a long time boiling in my head, that out of the following two stored procedures which one would perform better.
Proc 1
CREATE PROCEDURE GetEmployeeDetails #EmployeeId uniqueidentifier,
#IncludeDepartmentInfo bit
AS
BEGIN
SELECT * FROM Employees
WHERE Employees.EmployeeId = #EmployeeId
IF (#IncludeDepartmentInfo = 1)
BEGIN
SELECT Departments.* FROM Departments, Employees
WHERE Departments.DepartmentId = Employees.DepartmentId
AND Employees.EmployeeId = #EmployeeId
END
END
Proc 2
CREATE PROCEDURE GetEmployeeDetails #EmployeeId uniqueidentifier,
#IncludeDepartmentInfo bit
AS
BEGIN
SELECT * FROM Employees
WHERE Employees.EmployeeId = #EmployeeId
SELECT Departments.* FROM Departments, Employees
WHERE Departments.DepartmentId = Employees.DepartmentId
AND Employees.EmployeeId = #EmployeeId
AND #IncludeDepartmentInfo = 1
END
the only difference between the two is use of 'if statment'.
if proc 1/proc 2 are called with alternating values of #IncludeDepartmentInfo then from my understanding proc 2 would perform better, because it will retain the same query plan irrespective of the value of #IncludeDepartmentInfo, whereas proc1 will change query plan in each call
answers are really appericated
PS: this is just a scenario, please don't go to the explicit query results but the essence of example. I am really particular about the query optimizer result (in both cases of 'if and where' and their difference), there are many aspects which I know could affect the performance which I want to avoid in this question.
SELECT Departments.* FROM Departments, Employees
WHERE Departments.DepartmentId = Employees.DepartmentId
AND Employees.EmployeeId = #EmployeeId
AND #IncludeDepartmentInfo = 1
When SQL compiles a query like this it must be compiled for any value of #IncludeDepartmentInfo. The resulted plan can well be one that scans the tables and performs the join and after that checks the variable, resulting in unnecessary I/O. The optimizer may be smart and move the check for the variable ahead of the actual I/O operations in the execution plan, but this is never guaranteed. This is why I always recommend to use explicit IFs in the T-SQL for queries that need to perform very differently based on a variable value (the typical example being OR conditions).
gbn's observation is also an important one: from an API design point of view is better to have a consistent return type (ie. always return the same shaped and number of result sets).
From a consistency perspective, number 2 will always return 2 datasets. Overloading aside, you wouldn't have a client code method that may be returns a result, maybe not.
If you reuse this code, the other calling client will have to know this flag too.
If the code does 2 different things, then why not 2 different stored procs?
Finally, it's far better practice to use modern JOIN syntax and separate joining from filtering. In this case, personally I'd use EXISTS too.
SELECT
D.*
FROM
Departments D
JOIN
Employees E ON D.DepartmentId = E.DepartmentId
WHERE
E.EmployeeId = #EmployeeId
AND
#IncludeDepartmentInfo = 1
When you use the 'if' statement, you may run only one query instead of two. I would think that one query would almost always be faster than two. Your point about query plans may be valid if the first query were complex and took a long time to run, and the second was trivial. However, the first query looks like it retrieves a single row based on a primary key - probably pretty fast every time. So, I would keep the 'if' - but I would test to verify.
The performance difference would be too small for anyone to notice.
Premature optimization is the root of all evil. Stop worrying about performance and start implementing features that make your customers smile.