SQL select count of all rows when using IF ELSE - sql

I have a situation when I use IF ELSE statement in SQL.
#searchString nvarchar(50),
#languageId int,
#count int,
#id int
IF(#count IS NOT NULL)
SELECT TOP (#count) Id, value
FROM TABLE1
WHERE (Id IN
(SELECT Id
FROM TABLE2
WHERE (Id = #id))) and languageId = #languageId AND value LIKE '%' + #searchString + '%'
ORDER BY value
ELSE
SELECT Id, value
FROM TABLE1
WHERE (Id IN
(SELECT Id
FROM TABLE2
WHERE (Id = #id))) and languageId = #languageId AND value LIKE '%' + #searchString + '%'
ORDER BY value
I would like to return number of all rows using
count(*) over() (or something similar)
(as I return only TOP count records for now), like it is answered here:
How to return total number of records with TOP * select
BUT: I wouldn't return this value for every instance, but I would like to return count just once.
Is there a way to do this with one query, or I have to write a separate query for this?
Any hint would be greatly appreciated!
EDIT: using SQL server 2008 r2.

I suggest you to use INNER JOIN, for Exemple with scripts:
{
SCRIPT
SELECT
l.localite_id,
p.patient_id,
p.patient_date_naissance,
p.patient_gsm, p.patient_tel
FROM
patient p
INNER JOIN localite l
ON l.localite_id = p.localite_id
INNER JOIN ville v
ON v.ville_id = l.ville_id
INNER JOIN gouvernorat g
ON v.gouv_id = g.gouv_id
INNER JOIN pays pays
ON pays.pays_id = g.pays_id
IF NEQ #patient_gsm# -1
WHERE p.patient_gsm like #patient_gsm#
AND p.patient_code like #patient_code#
ENDIF
END
}

Related

How to write if exist statement that would run a different select depending if it exists or not

I am trying to convert a sql if exists statement into a SSRS valid format to run a report on CRM.
CRM report doesn't accept the report on upload if I have a if exists method, I'm having troubles figuring out what I can use in its place.
IF EXISTS(select * from dbo.FC where dbo.FC.ContactID in (select dbo.AV.so_contactid from dbo.AV))
begin
select [STATEMENT 1]
from dbo.AV CRMAF_so_AV join
dbo.FC c
on CRMAF_so_AV.so_contactid = c.ContactID;
end
else
begin
select [STATEMENT 2]
from dbo.AV CRMAF_so_AV join
dbo.FA c
on CRMAF_so_AV.so_contactid = c.AccountID;
end;
I want to be able to either run the select [STATEMENT 1] if the condition is true else I want to run select [STATEMENT 2]
I have managed to get this to work by doing a LEFT JOIN instead of a JOIN.
select [STATEMENT 1 + 2 all columns needed]
from dbo.AV CRMAF_so_AV
left join dbo.FC c on CRMAF_so_AV.so_contactid = c.ContactID;
left join dbo.FA a on CRMAF_so_AV.so_contactid = a.AccountID;
This now runs if its an account or a contact.
Try this -
You have to put your entire statement in #select1 and #select1.
declare #statement1 as varchar(max);
declare #statement2 as varchar(max);
SET #statement1 = 'SELECT 1'
SET #statement2 = 'SELECT 2'
IF EXISTS(select * from dbo.FC where dbo.FC.ContactID in (select dbo.AV.so_contactid from dbo.AV))
BEGIN
EXEC (#statement1)
END
ELSE
BEGIN
EXEC (#statement2)
END
Instead of using if exists can you not get a count of records that meet the criteria and then if its 1 or greater run a different query as apposed to if it was equal to 0.
let me know if I am missing something what you are trying to achieve.
sorry i am unable to put comments due to having a new account so my reputation is low.
I think you need something like this:
WITH PreSelection AS (
SELECT
AV.ID AS AVID,
(SELECT TOP(1) c.ContactID FROM dbo.FC c WHERE c.ContactID = AV.so_contactid) AS ContactID,
(SELECT TOP(1) c.ContactID FROM dbo.FA c WHERE c.AccountID = AV.so_contactid) AS AccountID
FROM dbo.AV
)
SELECT
AVID,
ISNULL(
CASE WHEN ContactID IS NULL
THEN (SELECT TOP(1) AccountName FROM dbo.FA WHERE FA.AccountID = AccountID)
ELSE (SELECT TOP(1) LTRIM(RTRIM(ISNULL(FirstName, '') + ' ' + ISNULL(LastName, ''))) FROM dbo.FC WHERE FC.ContactID = ContactID)
END, '') AS ContactName
FROM PreSelection
A few things to note:
When SSRS evaluates query it expects the resluts to always have the same structure in terms of column names and types.
So you CANNOT do something like this..
IF #x=#y
BEGIN
SELECT Name, Age FROM employees
END
ELSE
BEGIN
SELECT DeptID, DeptName, DeptEMpCOunt FROM departments
END
... as this will return different types and column names and column counts.
What you CAN DO is this..
DECLARE #t TABLE(resultType int, colA varchar(128), colB int, colC varchar(128), colD int)
IF #x=#y
BEGIN
INSERT INTO #t(resultType, colA, ColB)
SELECT 1 as resultType, Name, Age FROM employees
END
ELSE
BEGIN
INSERT INTO #t(resultType, colB, colC, colD)
SELECT 2 AS resultType, DeptID, DeptName, DeptEmpCount FROM departments
END
SELECT * FROM #t
Al we are doing is creating a table that can handle all variations of the data and putting the results into whatever columns can accommodate that data type.
This will always return the same data structure so SSRS will be happy, then you will need to handle which columns to display your data from based on what gets returned, hence why I added the result type to the results so you can test that from within the report.

Performance is slow when Replacing/updating a string of a table row[bulk data] in SQL Server

I want to update formatted body column of the below main table called postswhich has below schema with dummy data-
Now, i want to replace/update a substring [i.e. source with the final URL] from the above formattedbody column.[total 5335 records in excel sheet]
For the same i've written below query -
DECLARE #LoopCounter INT = 1
DECLARE #SURL nvarchar(max)
DECLARE #FURL nvarchar(max)
WHILE ( #LoopCounter <= 5335)
BEGIN
SET #SURL = (select sourceURL from temptable where ID = #LoopCounter)
SET #FURL = (select [TargetURL] from temptable where ID = #LoopCounter)
update posts
Set FormattedBody=REPLACE(CAST(FormattedBody as NVarchar(Max)),#SURL,#FURL)
Where SectionID = 95 and postlevel=1 and CAST(FormattedBody as NVarchar(Max)) like '%' + #SURL + '%'
SET #LoopCounter = #LoopCounter + 1
END
temptable contains the data of the excel sheet [i.e. ID,sourceURL, and TargetURL].
Above query works as expected but the performance is too low, as it loops through all the rows from posts table [huge data] for 5335 records.
Currently, it updates only 3 records/minute.
Any suggestion/help is appreciated! :)
Thanks!
I think you don't need to use while and update, I would use UPDATE .. JOIN instead of while and update.
If there isn't any relationship between temptable and posts tables, you can use CROSS JOIN (Descartes product) let every sourceURL and [TargetURL] temptable columns to mapper with posts table then update.
UPDATE p
SET FormattedBody = REPLACE(CAST(FormattedBody as NVarchar(Max)),sourceURL,[TargetURL])
FROM posts p
CROSS JOIN
(
SELECT sourceURL,[TargetURL]
FROM temptable
where id <= 5335
) targetDt
Where p.SectionID = 95 and p.postlevel=1
I would suggest adding
and CAST(FormattedBody as NVarchar(Max)) like '%' + #SURL + '%'
to the where condition in the first place, because the way you wrote it, I think ALL the records are updated EACH time, whether the FormattedBody contains #SURL or not.

Add/Skip WHERE CLAUSE based on Condition

I have the below query that takes a TagId list from table variable and returns the list.
But I need to add that CategoryId WHERE condition only if #Tags has the records.
Is it possible to add a WHERE Condition only if my table variable has records otherwise run the same query with 1=1(Always true) and skip the category filter?
DECLARE #TagIdList NVARCHAR(100) = '22,25,47'
DECLARE #Tags TABLE (TagId INT);
WITH CSVtoTable
AS (
SELECT CAST('<XMLRoot><RowData>' + REPLACE(t.val, ',', '</RowData><RowData>') + '</RowData></XMLRoot>' AS XML) AS x
FROM (
SELECT #TagIdList
) AS t(val)
)
INSERT INTO #Tags (TagId)
SELECT m.n.value('.[1]', 'varchar(8000)') AS TagId
FROM CSVtoTable
CROSS APPLY x.nodes('/XMLRoot/RowData') m(n)
SELECT BookingId
,C.CategoryName
FROM Booking B
INNER JOIN Category C ON C.CategoryId = B.CategoryId
WHERE (
b.IsDeleted = 0
OR b.IsDeleted IS NULL
)
-- Add the below where condition only if #Tags has records, else use 1=1
AND C.CategoryId IN (
SELECT DISTINCT CategoryId
FROM CategoryXTag con
WHERE TagId IN (
SELECT TagId
FROM #Tags
)
)
Ultimately you only need to change the end of your query. If performance is an issue you might want to consider using two branches of an if block for each of the two cases even though it's technically possible to squeeze the logic into a single query that doesn't generally optimize as well.
AND
(
C.CategoryId IN (
SELECT CategoryId
FROM CategotryXTag
WHERE TagId IN (
SELECT TagId
FROM #Tags
)
)
OR
(SELECT COUNT(*) FROM #Tags) = 0
)
declare int #tagcount = (select count(*) from #Tags);
SELECT BookingId, C.CategoryName
FROM Booking B
INNER JOIN Category C
ON C.CategoryId = B.CategoryId
AND isnull(b.IsDeleted, 0) = 0
INNER JOIN CategoryXTag con
ON C.CategoryId = con.CategoryId
INNER JOIN #Tags tags
ON tags.TagID = con.TagID
OR #tagcount = 0;
if #tags is empty you might need to put one record in it with a value that would never by used and then or that value
if(#tagcount = 0) insert into #tags values (-100);
or tags.TagID = -100;
You don't need to modify your where clause. Instead, you achieve the same logic by filling #Tags with every TagId from CategoryXTag before running your final query if #Tags is empty after the initial insert:
if ((select count(*) from #Tags) = 0)
insert into #Tags
select distinct TagId
from CategoryXTag;
I'd declare a variable for the #Tags table:
declare #needTagsFilter bit
set #needTagsFilter = case when exists(select 1 from #Tags) then 1 else 0 end
and change the where clause like
AND (
(#needTagsFilter = 0) OR
(C.CategoryId IN (
SELECT DISTINCT CategoryId
FROM CategoryXTag con
WHERE TagId IN (
SELECT TagId
FROM #Tags
)
)
)
COUNT(*) is slower then exists. The downside of adding the count/exists directly to your original query is that SQL server might execute it for all rows.

How to compare two sub queries in one sql statement

I have a table tbl_Country, which contains columns called ID and Name. The Name column has multiple country names separated by comma, I want the id when I pass multiple country names to compare with Name column values. I am splitting the country names using a function - the sample query looks like this:
#country varchar(50)
SELECT *
FROM tbl_Country
WHERE (SELECT *
FROM Function(#Country)) IN (SELECT *
FROM Function(Name))
tbl_country
ID Name
1 'IN,US,UK,SL,NZ'
2 'IN,PK,SA'
3 'CH,JP'
parameter #country ='IN,SA'
i have to get
ID
1
2
NOTE: The Function will split the string into a datatable
Try this
SELECT * FROM tbl_Country C
LEFT JOIN tbl_Country C1 ON C1.Name=C.Country
Try this:
SELECT *
FROM tbl_Country C
WHERE ',' + #country + ',' LIKE '%,' + C.Name + ',%';
Basically, by specifying multiple values in a single column, you are violating the 1st NF. Therefore, the following might not be a good approach but provides the solution that you are looking for:
declare #country varchar(50)= 'IN,SA'
declare #counterend int
declare #counterstart int =1
declare #singleCountry varchar(10)
set #counterend = (select COUNT(*) from fnSplitStringList(#country))
create table #temp10(
id int
,name varchar(50))
while #counterstart<= #counterend
begin
;with cte as (
select stringliteral country
, ROW_NUMBER() over (order by stringliteral) countryseq
from fnSplitStringList(#country))
select #singleCountry = (select country FROM cte where countryseq=#counterstart)
insert into #temp10(id, name)
select * from tbl_country t1
where not exists (select id from #temp10 t2 where t1.id=t2.id)
and name like '%' + #singleCountry +'%'
set #counterstart= #counterstart+1
end
select * from #temp10
begin drop table #temp10 end
How it works: It splits the passed string and ranks it. Afterwards, it loops through all the records for every single Value(country) produced and inserts them into temptable.
try this,
select a.id FROM tbl_Country a inner join
(SELECT country FROM dbo.Function(#Country)) b on a.name=b.country

SQL WHERE ... IN clause with possibly null parameter

I am having some problems with my WHERE clause (using SQL 2008) . I have to create a stored procedure that returns a list of results based on 7 parameters, some of which may be null. The ones which are problematic are #elements, #categories and #edu_id. They can be a list of ids, or they can be null. You can see in my where clause that my particular code works if the parameters are not null. I'm not sure how to code the sql if they are null. The fields are INT in the database.
I hope my question is clear enough. Here is my query below.
BEGIN
DECLARE #elements nvarchar(30)
DECLARE #jobtype_id INT
DECLARE #edu_id nvarchar(30)
DECLARE #categories nvarchar(30)
DECLARE #full_part bit
DECLARE #in_demand bit
DECLARE #lang char(2)
SET #jobtype_id = null
SET #lang = 'en'
SET #full_part = null -- full = 1, part = 0
SET #elements = '1,2,3'
SET #categories = '1,2,3'
SET #edu_id = '3,4,5'
select
jobs.name_en,
parttime.fulltime_only,
jc.cat_id category,
je.element_id elem,
jt.name_en jobtype,
jobs.edu_id minEdu,
education.name_en edu
from jobs
left join job_categories jc
on (jobs.job_id = jc.job_id)
left join job_elements je
on (jobs.job_id = je.job_id)
left join job_type jt
on (jobs.jobtype_id = jt.jobtype_id)
left join education
on (jobs.edu_id = education.edu_id)
left join
(select job_id, case when (jobs.parttime_en IS NULL OR jobs.parttime_en = '') then 1 else 0 end fulltime_only from jobs) as parttime
on jobs.job_id = parttime.job_id
where [disabled] = 0
and jobs.jobtype_id = isnull(#jobtype_id,jobs.jobtype_id)
and fulltime_only = isnull(#full_part,fulltime_only)
-- each of the following clauses should be validated to see if the parameter is null
-- if it is, the clause should not be used, or the SELECT * FROM ListToInt... should be replaced by
-- the field evaluated: ie if #elements is null, je.element_id in (je.element_id)
and je.element_id IN (SELECT * FROM ListToInt(#elements,','))
and jc.cat_id IN (SELECT * FROM ListToInt(#categories,','))
and education.edu_id IN (SELECT * FROM ListToInt(#edu_id,','))
order by case when #lang='fr' then jobs.name_fr else jobs.name_en end;
END
Something like
and (#elements IS NULL OR je.element_id IN
(SELECT * FROM ListToInt(#elements,',')))
and (#categories IS NULL OR
jc.cat_id IN (SELECT * FROM ListToInt(#categories,',')))
....
should do the trick
je.element_id IN (SELECT * FROM ListToInt(#elements,',')) OR #elements IS NULL
that way for each one
Have you tried explicitly comparing to NULL?
and (#elements is null or je.element_id IN (SELECT * FROM ListToInt(#elements,','))
And so on.