Can select into add a new field to the resulting table? - sql-server

I've got a SQL statement in SQL Server 2005 that looks something like this:
SELECT * INTO #TempTable FROM FirstTable WHERE <complex where clause>
What I would really, really like is to have the resulting temp table have an extra field that is essentially an integer field counting from 1 up in the order the where clause returned the records.
Is this possible?
(Essentially, I want to be able to return a subset of the records returned from the first select statement, along the lines of "lines 45 through 179".)

Try this, using Row_Number:
-- insert into temp table
SELECT *,
ROW_NUMBER() OVER (ORDER BY SortColumn) AS SortColumn INTO #TempTable
FROM FirstTable
WHERE <complex where clause>
-- check the results and drop the table
SELECT * FROM #TempTable WHERE SortColumn BETWEEN 45 AND 179 ORDER BY SortColumn
DROP TABLE #TempTable
Obviously you'll need to replace SortColumn with whatever makes sense in your case
Edit:
If you're just trying to do paging, there are lots of examples of that:
http://www.davidhayden.com/blog/dave/archive/2005/12/30/2652.aspx
http://www.sqlteam.com/article/server-side-paging-using-sql-server-2005
http://www.google.com/search?q=sql+server+2005+paging

Related

Query tuning required for expensive query

Can someone help me to optimize the code? I have other way to optimize it by using compute column but we can not change the schema on prod as we are not sure how many API's are used to push data into this table. This table has millions of rows and adding a non-clustered index is not helping due to the query cost and it's going for a scan.
create table testcts(
name varchar(100)
)
go
insert into testcts(
name
)
select 'VK.cts.com'
union
select 'GK.ms.com'
go
DECLARE #list varchar(100) = 'VK,GK'
select * from testcts where replace(replace(name,'.cts.com',''),'.ms.com','') in (select value from string_split(#list,','))
drop table testcts
One possibility might be to strip off the .cts.com and .ms.com subdomain/domain endings before you insert or store the name data in your table. Then, use the following query instead:
SELECT *
FROM testcts
WHERE name IN (SELECT value FROM STRING_SPLIT(#list, ','));
Now SQL Server should be able to use an index on the name column.
If your values are always suffixed by cts.com or ms.com you could add that to the search pattern:
SELECT {YourColumns} --Don't use *
FROM dbo.testcts t
JOIN (SELECT CONCAT(SS.[value], V.Suffix) AS [value]
FROM STRING_SPLIT(#list, ',') SS
CROSS APPLY (VALUES ('.cts.com'),
('.ms.com')) V (Suffix) ) L ON t.[name] = L.[value];

sql server - insert if not exist else update

I have here a list of 100 types of item flavor. Then I have a table where I need a record for every item in every flavor. So if I have 50 items, I need 100 records for each of the 50 items in this table_A. so there will be a total of 100x50 records in this table at the end.
What I have now is a random mix of data and I know I don't have a record for each type of flavor for every item.
What I need help with is, an idea/algorithm so solve this problem. pseudo code would do. I have a table with all possible flavors (tbl_flavor) and a table with all 50 items (tbl_items). These two will dictate what needs to be put in table_A which is basically an inventory.
Please advise.
If I'm understanding your question correctly, a SQL Server EXCEPT query will help.
As already pointed out in the comments, here's how to get the matrix of items and flavors:
SELECT Items.Item, Flavors.Flavor
FROM Items
CROSS JOIN Flavors
Here's how to get the matrix of items and flavors, omitting the combinations that are already in your other table.
SELECT Items.Item, Flavors.Flavor
FROM Items
CROSS JOIN Flavors
EXCEPT SELECT Item, Flavor
FROM Table_A
So the INSERT becomes:
INSERT INTO Table_A (Item, Flavor)
SELECT Items.Item, Flavors.Flavor
FROM Items
CROSS JOIN Flavors
EXCEPT SELECT Item, Flavor
FROM Table_A
This query is untested because I'm not 100% sure about the question. If you post more detail I'll test it.
There are a few ways you can tackle this sort of problem. Here is psuedocode for one of those ways.
Update table
set Col1 = SomeValue
where MyKeys = Mykeys
if (##ROWCOUNT = 0)
begin
Insert table
(Cols)
Values
(Vals)
end
Or you can use MERGE. https://msdn.microsoft.com/en-us/library/bb510625.aspx
Try This
UPDATE MyTable
SET
ColumnToUpdate = NewValue
WHERE EXISTS
(
SELECT
1
FROM TableWithNewValue
WHERE ColumnFromTable1 = MyTable.ColumnName
)
INSERT INTO MyTable
(
Column1,
Column2,
...
ColumnN
)
SELECT
Value1,
Value2,
...
ValueN
FROM TableWithNewValue
WHERE NOT EXISTS
(
SELECT
1
FROM MyTable
WHERE ColumnName = TableWithNewValue.ColumnFromTable1
)

SQL WHERE NOT EXISTS (skip duplicates)

Hello I'm struggling to get the query below right. What I want is to return rows with unique names and surnames. What I get is all rows with duplicates
This is my sql
DECLARE #tmp AS TABLE (Name VARCHAR(100), Surname VARCHAR(100))
INSERT INTO #tmp
SELECT CustomerName,CustomerSurname FROM Customers
WHERE
NOT EXISTS
(SELECT Name,Surname
FROM #tmp
WHERE Name=CustomerName
AND ID Surname=CustomerSurname
GROUP BY Name,Surname )
Please can someone point me in the right direction here.
//Desperate (I tried without GROUP BY as well but get same result)
DISTINCT would do the trick.
SELECT DISTINCT CustomerName, CustomerSurname
FROM Customers
Demo
If you only want the records that really don't have duplicates (as opposed to getting duplicates represented as a single record) you could use GROUP BY and HAVING:
SELECT CustomerName, CustomerSurname
FROM Customers
GROUP BY CustomerName, CustomerSurname
HAVING COUNT(*) = 1
Demo
First, I thought that #David answer is what you want. But rereading your comments, perhaps you want all combinations of Names and Surnames:
SELECT n.CustomerName, s.CustomerSurname
FROM
( SELECT DISTINCT CustomerName
FROM Customers
) AS n
CROSS JOIN
( SELECT DISTINCT CustomerSurname
FROM Customers
) AS s ;
Are you doing that while your #Tmp table is still empty?
If so: your entire "select" is fully evaluated before the "insert" statement, it doesn't do "run the query and add one row, insert the row, run the query and get another row, insert the row, etc."
If you want to insert unique Customers only, use that same "Customer" table in your not exists clause
SELECT c.CustomerName,c.CustomerSurname FROM Customers c
WHERE
NOT EXISTS
(SELECT 1
FROM Customers c1
WHERE c.CustomerName = c1.CustomerName
AND c.CustomerSurname = c1.CustomerSurname
AND c.Id <> c1.Id)
If you want to insert a unique set of customers, use "distinct"
Typically, if you're doing a WHERE NOT EXISTS or WHERE EXISTS, or WHERE NOT IN subquery,
you should use what is called a "correlated subquery", as in ypercube's answer above, where table aliases are used for both inside and outside tables (where inside table is joined to outside table). ypercube gave a good example.
And often, NOT EXISTS is preferred over NOT IN (unless the WHERE NOT IN is selecting from a totally unrelated table that you can't join on.)
Sometimes if you're tempted to do a WHERE EXISTS (SELECT from a small table with no duplicate values in column), you could also do the same thing by joining the main query with that table on the column you want in the EXISTS. Not always the best or safest solution, might make query slower if there are many rows in that table and could cause many duplicate rows if there are dup values for that column in the joined table -- in which case you'd have to add DISTINCT to the main query, which causes it to SORT the data on all columns.
-- Not efficient at all.
And, similarly, the WHERE NOT IN or NOT EXISTS correlated subqueries can be accomplished (and give the exact same execution plan) if you LEFT OUTER JOIN the table you were going to subquery -- and add a WHERE . IS NULL.
You have to be careful using that, but you don't need a DISTINCT. Frankly, I prefer to use the WHERE NOT IN subqueries or NOT EXISTS correlated subqueries, because the syntax makes the intention clear and it's hard to go wrong.
And you do not need a DISTINCT in the SELECT inside such subqueries (correlated or not). It would be a waste of processing (and for WHERE EXISTS or WHERE IN subqueries, the SQL optimizer would ignore it anyway and just use the first value that matched for each row in the outer query). (Hope that makes sense.)

Get next sequence from table in insert statement to another table

I have 3 tables
Table_A has a bunch of rows
Table_B where rows are going to be inserted with data from Table_A
Table_C holds a number (integer) called code_number
I have a stored procedure (sp_getNextCode) that selects the current code_number from Table_C, creates and returns a varchar code string with this number (like yyyyMMdd + cast(code_number as varchar) or something) and updates the Table_C code_number with the next value (code_number+1)
So far so good.
Now I want to insert a number of rows from Table_A to Table_B WITHOUT THE USE OF CURSOR
using a
INSERT INTO TABLE_B
SELECT .... FROM TABLE_A
Again so far so good
The problem is that one of the values in the above insert statement has to be the output of the stored procedure sp_getNextCode.
I cannot use the stored procedure in the statement
I cannot create a function with the same code as sp_getNextCode as the functions cannot have INSERT/UPDATE/DELETE
I don't have the option of SQL Server 2012 (which has a sequence) only SQL Server 2008
Is there any way to achieve this or the only way is with cursors (I REALLY want to avoid the cursor cause im talking about thousands of rows that need to be inserted and it takes too long )
Sure, there is a way: Create a stored procedure to read from table_A, inserts ino table_b and updates table_C:
BEGIN TRANSACTION
SELECT #last_value=last_vale FROM Table_C;
SELECT #records_to_insert = COUNT(*)
FROM Table_A
WHERE <Conditions>
INSERT INTO TABLE_A
SELECT <Fields>,...., #last_value + ROW_NUMBER()
OVER(ORDER BY <some ordering criteria>)
FROM TABLE_A
WHERE <Conditions>
UPATE Table_C
SET last_value = #last_value + #records_to_insert +1
COMMIT TRANSACTION
I am ommiting some details as the transformation of the numbers to the formatted code, exception handling and rollback, but I hope you can get the idea.
The trick is to use the ROW_NUMBER() OVER (ORDER BY...) function to obtain a unique number for each row.
http://msdn.microsoft.com/en-us/library/ms186734.aspx

Is there a way to optimize the query given below

I have the following Query and i need the query to fetch data from SomeTable based on the filter criteria present in the Someothertable. If there is nothing present in SomeOtherTable Query should return me all the data present in SomeTable
SQL SERVER 2005
SomeOtherTable does not have any indexes or any constraint all fields are char(50)
The Following Query work fine for my requirements but it causes performance problems when i have lots of parameters.
Due to some requirement of Client, We have to keep all the Where clause data in SomeOtherTable. depending on subid data will be joined with one of the columns in SomeTable.
For example the Query can can be
SELECT
*
FROM
SomeTable
WHERE
1=1
AND
(
SomeTable.ID in (SELECT DISTINCT ID FROM SomeOtherTable WHERE Name = 'ABC' and subid = 'EF')
OR
0=(SELECT Count(1) FROM SomeOtherTable WHERE spName = 'ABC' and subid = 'EF')
)
AND
(
SomeTable.date =(SELECT date FROM SomeOtherTable WHERE Name = 'ABC' and subid = 'Date')
OR
0=(SELECT Count(1) FROM SomeOtherTable WHERE spName = 'ABC' and subid = 'Date')
)
EDIT----------------------------------------------
I think i might have to explain my problem in detail:
We have developed an ASP.net application that is used to invoke parametrize crystal reports, parameters to the crystal reports are not passed using the default crystal reports method.
In ASP.net application we have created wizards which are used to pass the parameters to the Reports, These parameters are not directly consumed by the crystal report but are consumed by the Query embedded inside the crystal report or the Stored procedure used in the Crystal report.
This is achieved using a table (SomeOtherTable) which holds parameter data as long as report is running after which the data is deleted, as such we can assume that SomeOtherTable has max 2 to 3 rows at any given point of time.
So if we look at the above query initial part of the Query can be assumed as the Report Query and the where clause is used to get the user input from the SomeOtherTable table.
So i don't think it will be useful to create indexes etc (May be i am wrong).
SomeOtherTable does not have any
indexes or any constraint all fields
are char(50)
Well, there's your problem. There's nothing you can do to a query like this which will improve its performance if you create it like this.
You need a proper primary or other candidate key designated on all of your tables. That is to say, you need at least ONE unique index on the table. You can do this by designating one or more fields as the PK, or you can add a UNIQUE constraint or index.
You need to define your fields properly. Does the field store integers? Well then, an INT field may just be a better bet than a CHAR(50).
You can't "optimize" a query that is based on an unsound schema.
Try:
SELECT
*
FROM
SomeTable
LEFT JOIN SomeOtherTable ON SomeTable.ID=SomeOtherTable.ID AND Name = 'ABC'
WHERE
1=1
AND
(
SomeOtherTable.ID IS NOT NULL
OR
0=(SELECT Count(1) FROM SomeOtherTable WHERE spName = 'ABC')
)
also put 'with (nolock)' after each table name to improve performance
The following might speed you up
SELECT *
FROM SomeTable
WHERE
SomeTable.ID in
(SELECT DISTINCT ID FROM SomeOtherTable Where Name = 'ABC')
UNION
SELECT *
FROM SomeTable
Where
NOT EXISTS (Select spName From SomeOtherTable Where spName = 'ABC')
The UNION will effectivly split this into two simpler queries which can be optiomised separately (depends very much on DBMS, table size etc whether this will actually improve performance -- but its always worth a try).
The "EXISTS" key word is more efficient than the "SELECT COUNT(1)" as it will return true as soon as the first row is encountered.
Or check if the value exists in db first
And you can remove the distinct keyword in your query, it is useless here.
if EXISTS (Select spName From SomeOtherTable Where spName = 'ABC')
begin
SELECT *
FROM SomeTable
WHERE
SomeTable.ID in
(SELECT ID FROM SomeOtherTable Where Name = 'ABC')
end
else
begin
SELECT *
FROM SomeTable
end
Aloha
Try
select t.* from SomeTable t
left outer join SomeOtherTable o
on t.id = o.id
where (not exists (select id from SomeOtherTable where spname = 'adbc')
OR spname = 'adbc')
-Edoode
change all your select statements in the where part to inner jons.
the OR conditions should be union all-ed.
also make sure your indexing is ok.
sometimes it pays to have an intermediate table for temp results to which you can join to.
It seems to me that there is no need for the "1=1 AND" in your query. 1=1 will always evaluate to be true, leaving the software to evaluate the next part... why not just skip the 1=1 and evaluate the juicy part?
I am going to stick to my original Query.

Resources