SQL IN Clause replacement Temp table - sql

My query is :
Select *
from Person
where KV_CODE IN('','',''......1000 values here)
How to write this list of values in a temp table so that I can replace IN clause with a join to increase performance.
This list of values is coming on the basis of random selection by user and is stored in a Java collection.

Select * from Person P INNER JOIN #Temp T ON T.KV_CODE = P.KV_CODE
You can apply INNER JOIN on Temp Table similar to Normal Tables.

select *
from Person
where KV_CODE in (
select KV_CODE
from TempTable
)
This will compare the KV_CODE of Person to the KV_CODE of TempTable. If there are matches, it will intersect them, meaning your first select will print only those rows.
select *
from Person p
join TempTable tmp
on p.KV_CODE = tmp.KV_CODE
This will join the two tables and display the matching rows from both tables.
Unless your question is "how to populate a temporary table from a java collection"

Newer database solutions optimize this already. There is not much difference between IN clause and Join as optimizer figures out this aspect and execute query by appropriate path.
If you still wish, here is what you have to do.
if you are using Oracle,
you can create a session scope or transaction scope temporary table.
Insert data into this temporary table
Fire query like
SELECT *
FROM PERSONS T1,
TEMP_TABLE_NAME_HERE T2
WHERE T1.KV_CODE = T2.KV_CODE
However, a better solution is to avoid temp table creation during run time. You can actually create a permanent table in your application database with some unique key to identify your session (to isolate cross session impacts, i.e 2 users using same functionality).
CREATE TABLE KV_TEMP_TABLE
(SESSION_ID VARCHAR2(100),
KV_CODE VARCHAR2(100)
);
--Adjust datatypes suitably
Then your query should look like
SELECT * FROM PERSONS T1, KV_TEMP_TABLE T2
WHERE T2.SESSION_ID = ?
AND T1.KV_CODE = T2.KV_CODE
--Bind your session id
Before issuing this query, you have to populate data into KV_TEMP_TABLE using normal insert statements (along with a session id).

Use this example to populates a temp table :
DECLARE #t TABLE
(
EmployeeID INT,
Certs VARCHAR(8000)
)
INSERT #t VALUES (1,'B.E.,MCA, MCDBA, PGDCA'), (2,'M.Com.,B.Sc.'), (3,'M.Sc.,M.Tech.')
SELECT EmployeeID,
LTRIM(RTRIM(m.n.value('.[1]','varchar(8000)'))) AS Certs
FROM
(
SELECT EmployeeID,CAST('<XMLRoot><RowData>' + REPLACE(Certs,',','</RowData><RowData>') + '</RowData></XMLRoot>' AS XML) AS x
FROM #t
)t
CROSS APPLY x.nodes('/XMLRoot/RowData')m(n)
Once the temp table #t is populated, it can be used with JOINs to get the desired output.

Related

assign only particular column values to a temp table from select query

I am having below query that will return 6 columns and i want only assign particular column (converted_skus) results to temporary table and i need to do further processing on that column only ..
I am not sure how can i assign only particular column values to temporary table where as other columns are not needed for further processing
here is my query
SELEct distinct
clpAct.pk_cert,CCM.leg_sku_des,CCM.converted_sku_des,CCM.converted_skus,
esitrans.pk_cert,esitrans.part_id from Clp_Active clpAct
inner join transfertable esitrans
ON clpact.pk_cert = esitrans.pk_cert
INNER JOIN pass_conversion CCM
ON esitrans.part_id = CCM.part_number
where clpAct.subscription_key = #subKey
Would any one please help on this query that would be very grateful to me.
Many thanks in advance
I am using sql server as DB
if you don't need the other columns, then just select your required column only and insert it into the temp table. like this
create table #temp
(
converted_skus varchar(50)
)
insert into #temp
(
converted_skus
)
SELEct distinct
CCM.converted_skus
from Clp_Active clpAct
inner join transfertable esitrans
ON clpact.pk_cert = esitrans.pk_cert
INNER JOIN pass_conversion CCM
ON esitrans.part_id = CCM.part_number
where clpAct.subscription_key = #subKey
now you have only the required column and values in the temp table #temp

How can I grab one column from a subquery and insert that column into another table where I can query off of those ID's in another data table?

Trying to explain this the best I can, I have a subquery which is looking for some document information in one table, I need to then use an INSERT INTO to ONLY take the document IDs that are returned and query them in a separate data table.
This is what Im working with right now
use DATABASE
Select * into #Audit
From [dbo].[workflow] A
Where object_id IN
(
Select DISTINCT ChangeHistory.document_id, ChangeHistory.account_number,
min(timestamp)
from [dbo].[xip_workflow] A
INNER JOIN (select B.*
from [dbo].[changehistory] B
where B.doc_status like ('New')
and user_login_name like ('System')
and button_push like (' ')
and B.account_number in ('11111111')
and B.work_queue_system_name in ('r_queue')
and B.document_type in ('A1','A2','A3')
and timestamp > '4/11/2017') ChangeHistory
ON ChangeHistory.[document_id] = A.[object_id]
group by document_id, ChangeHistory.account_number)

Query for missing items in a table

I have a table of airport code pairs:
|iata|icao|
-----------
|ORD |KORD|
|JFK |KJFK|
|LAX |KLAX|
|SFO |KSFO|
I want to run a query that will return the codes that do not exist in this table, so if I run a query (against the iata column) containing ATL,ORD,MIA,SFO it would return ATL and MIA since neither of those exist in my table. Is this possible?
If you have a query that runs code, here is one way:
select mc.*
from (<your query goes here>) mc
where mc.iata not in (select iata from AirportCodePairs acp)
You can also do this with a left outer join and comparison to NULL. I would recommend an index on iata in the pairs table.
Or, if you don't have a query, you can do:
select mc.*
from (select 'ATL' as code union all
select 'ORD' union all
select 'MIA' union all
select 'SFO'
) mc
where mc.iata not in (select iata from AirportCodePairs acp)
You can create a table with the values you are searching for and then do a JOIN:
CREATE TABLE tmp ( code char(3) NOT NULL);
INSERT INTO tmp (code) VALUES ('ATL'), ('ORD'), ('MIA'), ('SFO');
SELECT code FROM tmp
LEFT OUTER JOIN airportcode as ac ON tmp.code = ac.iata
WHERE ac.iata IS NULL
in oracle you could use minus command example
select your_columns from tableA minus select your_columns from tableB
note that both must have same columns and types and lengths or it will not work.
if type is different do cast, to_char, to_date or whatever function is necessary to get types the same. Note if you do have to do one of these or any oracle function call in where clause then use function based indexes. For example, if to_upper is called in where clause like this
select * from tableName a where to_upper(last_name)='SIMPSON'
an index on this would be created as follows
create index ixt on tableName(to_uppper(last_name));

SQL Server Table-Value Function and Except Combination performance

I have a table (Resources with about 18000 records) and a Table-Value Function with this body :
ALTER FUNCTION [dbo].[tfn_GetPackageResources]
(
#packageId int=null,
#resourceTypeId int=null,
#resourceCategoryId int=null,
#resourceGroupId int=null,
#resourceSubGroupId int=null
)
RETURNS TABLE
AS
RETURN
(
SELECT Resources.*
FROM Resources
INNER JOIN ResourceSubGroups ON Resources.ResourceSubGroupId=ResourceSubGroups.Id
INNER JOIN ResourceGroups ON ResourceSubGroups.ResourceGroupId=ResourceGroups.Id
INNER JOIN ResourceCategories ON ResourceGroups.ResourceCategoryId=ResourceCategories.Id
INNER JOIN ResourceTypes ON ResourceCategories.ResourceTypeId=ResourceTypes.Id
WHERE
(#resourceSubGroupId IS NULL OR ResourceSubGroupId=#resourceSubGroupId) AND
(#resourceGroupId IS NULL OR ResourceGroupId=#resourceGroupId) AND
(#resourceCategoryId IS NULL OR ResourceCategoryId=#resourceCategoryId) AND
(#resourceTypeId IS NULL OR ResourceTypeId=#resourceTypeId) AND
(#packageId IS NULL OR PackageId=#packageId)
)
now I make a query like this :
SELECT id
FROM dbo.tfn_GetPackageResources(#sourcePackageId,null,null,null,null)
WHERE id not in(
SELECT a.Id
FROM dbo.tfn_GetPackageResources(#sourcePackageId,null,null,null,null) a INNER JOIN
dbo.tfn_GetPackageResources(#comparePackageId,null,null,null,null) b
ON a.No = b.No AND
a.UnitCode=b.UnitCode AND
a.IsCompound=b.IsCompound AND
a.Title=b.Title
)
This query takes about 10 seconds!(Although each part query runs extremely fast but the whole one take time) I check it with LEFT JOIN and NOT EXISTS but the result was same.
but if I run the query on the Resources table directly it only takes one second or less! the fast query is :
select * from resources where id not in (select id from resources)
how can I solve it?
Your UDF is expanded like a macro.
So your complete query has
9 INNER JOINs in the IN clause
4 INNER JOINs in the main SELECT.
You apply (... IS NULL OR ...) 15 times in total for each of your WHERE clauses.
Your idea of clever code reuse fails because of this expansionSQL does not usually lend itself to this reuse.
Keep it simple:
SELECT
R.id
FROM
Resources R
WHERE
R.PackageId = #sourcePackageId
AND
R.id not in (
SELECT a.Id
FROM Resources a
INNER JOIN
Resources b
ON a.No = b.No AND
a.UnitCode=b.UnitCode AND
a.IsCompound=b.IsCompound AND
a.Title=b.Title
WHERE
a.PackageId = #sourcePackageId
AND
b.PackageId = #comparePackageId
)
For more, see my other answers here:
Why is a UDF so much slower than a subquery?
Profiling statements inside a User-Defined Function
Does query plan optimizer works well with joined/filtered table-valued functions?
Table Valued Function where did my query plan go?
In your function, declare the type of the table it returns, and include a primary key. This way, the ID filter will be able to look up the IDs more efficiently.
See http://msdn.microsoft.com/en-us/library/ms191165(v=sql.105).aspx for the syntax.
Thing you should try is to break one complicated query into multiple simple ones that store their results in temporary tables, this way one complicated execution plan will be replaced by several simple plans whose total execution time might be shorter then the execution time of a complicated execution plan:
SELECT *
INTO #temp1
FROM dbo.tfn_GetPackageResources(#sourcePackageId,null,null,null,null)
SELECT *
INTO #temp2
FROM dbo.tfn_GetPackageResources(#comparePackageId,null,null,null,null)
SELECT a.Id
INTO #ids
FROM #temp1 a
INNER JOIN
#temp2 b ON
a.No = b.No
AND a.UnitCode=b.UnitCode
AND a.IsCompound=b.IsCompound
AND a.Title=b.Title
SELECT id
FROM #temp1
WHERE id not in(
SELECT Id
FROM #ids
)
-- you can also try replacing the above query with this one if it performs faster
SELECT id
FROM #temp1 t
WHERE NOT EXISTS
(
SELECT Id FROM #ids i WHERE i.Id = t.id
)

Converting a nested sql where-in pattern to joins

I have a query that is returning the correct data to me, but being a developer rather than a DBA I'm wondering if there is any reason to convert it to joins rather than nested selects and if so, what it would look like.
My code currently is
select * from adjustments where store_id in (
select id from stores where original_id = (
select original_id from stores where name ='abcd'))
Any references to the better use of joins would be appreciated too.
Besides any likely performance improvements, I find following much easier to read.
SELECT *
FROM adjustments a
INNER JOIN stores s ON s.id = a.store_id
INNER JOIN stores s2 ON s2.original_id = s.original_id
WHERE s.name = 'abcd'
Test script showing my original fault in ommitting original_id
DECLARE #Adjustments TABLE (store_id INTEGER)
DECLARE #Stores TABLE (id INTEGER, name VARCHAR(32), original_id INTEGER)
INSERT INTO #Adjustments VALUES (1), (2), (3)
INSERT INTO #Stores VALUES (1, 'abcd', 1), (2, '2', 1), (3, '3', 1)
/*
OP's Original statement returns store_id's 1, 2 & 3
due to original_id being all the same
*/
SELECT * FROM #Adjustments WHERE store_id IN (
SELECT id FROM #Stores WHERE original_id = (
SELECT original_id FROM #Stores WHERE name ='abcd'))
/*
Faulty first attempt with removing original_id from the equation
only returns store_id 1
*/
SELECT a.store_id
FROM #Adjustments a
INNER JOIN #Stores s ON s.id = a.store_id
WHERE s.name = 'abcd'
If you would use joins, it would look like this:
select *
from adjustments
inner join stores on stores.id = adjustments.store_id
inner join stores as stores2 on stores2.original_id = stores.original_id
where stores2.name = 'abcd'
(Apparently you can omit the second SELECT on the stores table (I left it out of my query) because if I'm interpreting your table structure correctly,
select id from stores where original_id = (select original_id from stores where name ='abcd')
is the same as
select * from stores where name ='abcd'.)
--> edited my query back to the original form, thanks to Lieven for pointing out my mistake in his answer!
I prefer using joins, but for simple queries like that, there is normally no performance difference. SQL Server treats both queries the same internally.
If you want to be sure, you can look at the execution plan.
If you run both queries together, SQL Server will also tell you which query took more resources than the other (in percent).
A slightly different approach:
select * from adjustments a where exists
(select null from stores s1, stores s2
where a.store_id = s1.id and s1.original_id = s2.original_id and s2.name ='abcd')
As say Microsoft here:
Many Transact-SQL statements that include subqueries can be
alternatively formulated as joins. Other questions can be posed only
with subqueries. In Transact-SQL, there is usually no performance
difference between a statement that includes a subquery and a
semantically equivalent version that does not. However, in some cases
where existence must be checked, a join yields better performance.
Otherwise, the nested query must be processed for each result of the
outer query to ensure elimination of duplicates. In such cases, a join
approach would yield better results.
Your case is exactly when Join and subquery gives the same performance.
Example when subquery can not be converted to "simple" JOIN:
select Country,TR_Country.Name as Country_Translated_Name,TR_Country.Language_Code
from Country
JOIN TR_Country ON Country.Country=Tr_Country.Country
where country =
(select top 1 country
from Northwind.dbo.Customers C
join
Northwind.dbo.Orders O
on C.CustomerId = O.CustomerID
group by country
order by count(*))
As you can see, every country can have different name translations so we can not just join and count records (in that case, countries with larger quantities of translations will have more record counts)
Of cource, you can can transform this example to:
JOIN with derived table
CTE
but it is an other tale-)