Replace function is very slow in SQL Server - sql-server

I am trying to execute the query as below in SQL Server but it is very slow due to the Replace function, can anyone help in optimizing the query to run very fast
SELECT
dbo.Orders.OrigID
FROM
dbo.Orders
INNER JOIN
dbo.OrderedReports ON dbo.Orders.OrigID = dbo.OrderedReports.OrderID
WHERE
(REPLACE(Orders.Email, '^^', '''') = 'Khengtjinyap#gmail.com')

One simple long term fix here would be to simply remove the ^^ symbols from the email before you insert the data. In order to deal with the email data which already exists in the Orders table, you could do the following one-time update:
UPDATE Orders
SET Email = REPLACE(Email, '^^', '')
WHERE Email LIKE '%^^%';
You could also create a new column which contains the cleaned up email addresses. Once you have made this change, just use a direct equality comparison in your query, which can now also use an index on the Email column.

Related

How to create a "Ghost Table" in SQL Server based off of other tables?

I need to create a "ghost" table in SQL Server, which doesn't actually exist but is a result set of a SQL Query. Pseudo code is below:
SELECT genTbl_col1, genTblcol2
FROM genTbl;
However, "genTbl" is actually:
SELECT table1.col AS genTbl_col1,
table2.col AS genTbl_col2
FROM table1 INNER JOIN table2 ON (...)
In other words, I need that every time a query is run on the server trying to select from "genTbl", it simply creates a result set from the query and treats it like a real table.
The situation is that I have a software that runs queries on a database. I need to modify it, but I cannot change the software itself, so I need to trick it into thinking it can actually query "genTbl", when it actually doesn't exist but is simply a query of other tables.
To clarify, the query would have to be a sort of procedure, available by default in the database (i.e. every time there is a query for "genTbl").
Use #TMP
SELECT genTbl_col1, genTblcol2
INTO #TMP FROM genTbl;
It exists only in current session. You can also use ##TMP for all sessions.

Verifying Syntax of a Massive SQL Update Command

I'm new to SQL Server and am doing some cleanup of our transaction database. However, to accomplish the last step, I need to update a column in one table of one database with the value from another column in another table from another database.
I found a SQL update code snippet and re-wrote it for our own needs but would love someone to give it a once over before I hit the execute button since the update will literally affect hundreds of thousands of entries.
So here are the two databases:
Database 1: Movement
Table 1: ItemMovement
Column 1: LongDescription (datatype: text / up to 40 char)
Database 2: Item
Table 2: ItemRecord
Column 2: Description (datatype: text / up to 20 char)
Goal: set Column1 from db1 to the value of Colum2 from db2.
Here is the code snippet:
update table1
set table1.longdescription = table2.description
from movement..itemmovement as table1
inner join item..itemrecord as table2 on table1.itemcode = table2.itemcode
where table1.longdescription <> table2.description
I added the last "where" line to prevent SQL from updating the column where it already matches the source table.
This should execute faster and just update the columns that have garbage. But as it stands, does this look like it will run? And lastly, is it a straightforward process, using SQL Server 2005 Express to just backup the entire Movement db before I execute? And if it messes up, just restore it?
Alternatively, is it even necessary to re-cast the tables as table1 and table 2? Is it valid to execute a SQL query like this:
update movement..itemmovement
set itemmovement.longdescription = itemrecord.description
from movement..itemmovement
inner join item..itemrecord on itemmovement.itemcode = itemrecord.itemcode
where itemmovement.longdescription <> itemrecord.description
Many thanks in advance!
You don't necessarily need to alias your tables but I recommend you do for faster typing and reduce the chances of making a typo.
update m
set m.longdescription = i.description
from movement..itemmovement as m
inner join item..itemrecord as i on m.itemcode = i.itemcode
where m.longdescription <> i.description
In the above query I have shortened the alias using m for itemmovement and i for itemrecord.
When a large number of records are to be updated and there's question whether it would succeed or not, always make a copy in a test database (residing on a test server) and try it out over there. In this case, one of the safest bet would be to create a new field first and call it longdescription_text. You can make it with SQL Server Management Studio Express (SSMS) or using the command below:
use movement;
alter table itemmovement add column longdescription_test varchar(100);
The syntax here says alter table itemmovement and add a new column called longdescription_test with datatype of varchar(100). If you create a new column using SSMS, in the background, SSMS will run the same alter table statement to create a new column.
You can then execute
update m
set m.longdescription_test = i.description
from movement..itemmovement as m
inner join item..itemrecord as i on m.itemcode = i.itemcode
where m.longdescription <> i.description
Check data in longdescription_test randomly. You can actually do a spot check faster by running:
select * from movement..itemmovement
where longdescription <> longdescription_test
and longdescription_test is not null
If information in longdescription_test looks good, you can change your update statement to set m.longdescription = i.description and run the query again.
It is easier to just create a copy of your itemmovement table before you do the update. To make a copy, you can just do:
use movement;
select * into itemmovement_backup from itemmovement;
If update does not succeed as desired, you can truncate itemmovement and copy data back from itemmovement_backup.
Zedfoxus provided a GREAT explanation on this and I appreciate it. It is excellent reference for next time around. After reading over some syntax examples, I was confident enough in being able to run the second SQL update query that I have in my OP. Luckily, the data here is not necessarily "live" so at low risk to damage anything, even during operating hours. Given the nature of the data, the updated executed perfectly, updating all 345,000 entries!

SQL Server 2008 - Force SQL Server to Return a Row when the where Clause Returns No Rows

I have a really simple SQL Server query that doesn't return a value. I'd like to see my query return a single row set with a space in it, but I can't seem to get it after a lot of time trying and searching! So, I've got to be doing something wrong and I really feel kind of dumb for having to post such a simple thing, but I can't seem to get it...
Here's the Select:
Select Session from Logins where Session = '123'
In my table the value '123' does not exist under the Session column...
So, I need this simple query to return a space as the value and not return an empty row set.
I've tried ISNULL, COALESCE and the little known IFNULL, all to no effect.
Interestingly, if I remove the where clause from the query it returns multiple rows correctly, none of them as nulls - as SQL Server should do, but when I put in my where clause in I get an empty row set. What I can't understand is why!
All you SQL Server gurus out there, could you please help me to develop a query that returns one column with one row that has a space in it when there is no return set for a where clause?
Thanks in advance,
Usually, you would want to perform this sort of logic in the client side rather than directly in the query.
But here is one way you can do it in pure SQL by putting your query in a CTE. Not sure if the CTE will get run twice though.
with cte as (
select session
from Logins
where session = '123'
)
select session
from cte
union all
select ' ' as session
where not exists (select null from cte)

Creating a new row in SSRS dataset SQL query to use in a report parameter

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.

Grouping SQL Server requests

This question is not about grouping in SQL.
Let's assume an application server sitting between UI of the application and a SQL Server. This server of course makes SQL requests to the SQL Server. For each such request there is some non-trivial overhead. I am curious whether there is a way to group several requests and send them together, reducing the communication overhead.
For example the server wants to make queries such as
Select * from teams...
and
Select * from users...
and instead of processing them separately it will send something like a List<sqlRequest> and receive back a List<sqlResponse> (of course transparently to the programmer).
In my particular case I am using SQL Server. On a more general note, is there any SQL database server / SQL mapping framework capable of this? Is (would be) the performance gain caused by this worth the effort at all?
You can achieve performance gains if
The second result-set is based on the first
The first result set is expensive to create
Consider the following
CREATE PROC GetTeamsAndUsersForACity(#CityId Int)
BEGIN
DECLARE #Teams as Table (TeamId int, TeamName varchar(10))
INSERT into #Teams
SELECT TeamId, TeamName
FROM
Teams
WHERE
CityId = #CityID
SELECT TeamId, TeamName FROM #Teams
SELECT
UserId, UserName, TeamId
FROM
Users
WHERE
TeamId in (Select TeamID FROM #Teams)
END
Notice how we're re-using the #teams to get the users and the associated teams without requerying the teams table.
You could achieve these result sets in other ways. For example you could retrieve the teamids from the first result and then pass that back SQL Server for the second set.
You could also requerying team again e.g. WHERE TeamId in (Select TeamID FROM Teams where CityID = #CityID).
You could also just get in one resultset select * from teams inner join users....Where city id= #cityid and then split them out on the client.
The relative performance of each solution will differ on the size of first set and the query time of generating the first resultset so you'll need to test to see which is right for your situation.
As for how to consume GetTeamsAndUsersForACity from the client. Assuming you're using .NET you can
Use SqlDataReader.NextResult
Use LINQ to SQL via the IMultipleResults interface
Use DataSet.Load Method (IDataReader, LoadOption, String[]) or one of the DataAdapter.Fill()
If you're using an ORM you'll have to check for support of multiple results form a Stored procedure

Resources