Asked  10 Months ago    Answers:  5   Viewed   9 times

I have a store procedure which i have planned to use for search and get all values.

Scenario: If the parameter passed is NULL it should return all the values of the table and if the parameter passed is not NULL it should return the values according to the condition which is in LIKE.

//Query:

ALTER procedure [dbo].[usp_GetAllCustomerDetails]
(
@Keyword nvarchar(20) =  null
)
As
Begin

Select CustomerId,CustomerName,CustomerTypeName,CustomerCode,CategoryName,CustomerMobile,CustomerEmail,CustomerAddress,CustomerCity,CustomerState,Pincode
from tblCustomerMaster CM
inner join dbo.tblCustomerTypeMaster CTM on CTM.CustomerTypeId = CM.CustomerType
inner join dbo.tblCategoryMaster CCM on CCM.CategoryId= CM.CustomerCategory
where CustomerName like '%'+@Keyword+'%' 

In the above query it returns no values when i execute since the NULL is assumed as string by SQL, so what should i write in the where clause to get the desired output?

 Answers

3

You can use condition like this in you where clause

where @Keyword is null or CustomerName like '%' + @Keyword + '%' 
Thursday, August 5, 2021
1

Visibility Warning: Don't the other answer. It will give incorrect values. Read on for why it's wrong.


Given the kludge needed to make UPDATE with OUTPUT work in SQL Server 2008 R2, I changed my query from:

UPDATE BatchReports  
SET IsProcessed = 1
OUTPUT inserted.BatchFileXml, inserted.ResponseFileXml, deleted.ProcessedDate
WHERE BatchReports.BatchReportGUID = @someGuid

to:

SELECT BatchFileXml, ResponseFileXml, ProcessedDate FROM BatchReports
WHERE BatchReports.BatchReportGUID = @someGuid

UPDATE BatchReports
SET IsProcessed = 1
WHERE BatchReports.BatchReportGUID = @someGuid

Basically I stopped using OUTPUT. This isn't so bad as Entity Framework itself uses this very same hack!

Hopefully 2012 2014 2016 2018 2019 2020 will have a better implementation.


Update: using OUTPUT is harmful

The problem we started with was trying to use the OUTPUT clause to retrieve the "after" values in a table:

UPDATE BatchReports
SET IsProcessed = 1
OUTPUT inserted.LastModifiedDate, inserted.RowVersion, inserted.BatchReportID
WHERE BatchReports.BatchReportGUID = @someGuid

That then hits the well-know limitation ("won't-fix" bug) in SQL Server:

The target table 'BatchReports' of the DML statement cannot have any enabled triggers if the statement contains an OUTPUT clause without INTO clause

Workaround Attempt #1

So we try something where we will use an intermediate TABLE variable to hold the OUTPUT results:

DECLARE @t TABLE (
   LastModifiedDate datetime,
   RowVersion timestamp, 
   BatchReportID int
)
  
UPDATE BatchReports
SET IsProcessed = 1
OUTPUT inserted.LastModifiedDate, inserted.RowVersion, inserted.BatchReportID
INTO @t
WHERE BatchReports.BatchReportGUID = @someGuid

SELECT * FROM @t

Except that fails because you're not allowed to insert a timestamp into the table (even a temporary table variable).

Workaround Attempt #2

We secretly know that a timestamp is actually a 64-bit (aka 8 byte) unsigned integer. We can change our temporary table definition to use binary(8) rather than timestamp:

DECLARE @t TABLE (
   LastModifiedDate datetime,
   RowVersion binary(8), 
   BatchReportID int
)
  
UPDATE BatchReports
SET IsProcessed = 1
OUTPUT inserted.LastModifiedDate, inserted.RowVersion, inserted.BatchReportID
INTO @t
WHERE BatchReports.BatchReportGUID = @someGuid

SELECT * FROM @t

And that works, except that the value are wrong.

The timestamp RowVersion we return is not the value of the timestamp as it existed after the UPDATE completed:

  • returned timestamp: 0x0000000001B71692
  • actual timestamp: 0x0000000001B71693

That is because the values OUTPUT into our table are not the values as they were at the end of the UPDATE statement:

  • UPDATE statement starting
    • modifies row
      • timestamp is updated (e.g. 2 ? 3)
    • OUTPUT retrieves new timestamp (i.e. 3)
    • trigger runs
      • modifies row again
        • timestamp is updated (e.g. 3 ? 4)
  • UPDATE statement complete
  • OUTPUT returns 3 (the wrong value)

This means:

  • We do not get the timestamp as it exists at the end of the UPDATE statement (4)
  • Instead we get the timestamp as it was in the indeterminate middle of the UPDATE statement (3)
  • We do not get the correct timestamp

The same is true of any trigger that modifies any value in the row. The OUTPUT will not OUTPUT the value as of the end of the UPDATE.

This means you cannot trust OUTPUT to return any correct values ever.

This painful reality is documented in the BOL:

Columns returned from OUTPUT reflect the data as it is after the INSERT, UPDATE, or DELETE statement has completed but before triggers are executed.

How did Entity Framework solve it?

The .NET Entity Framework uses rowversion for Optimistic Concurrency. The EF depends on knowing the value of the timestamp as it exists after they issue an UPDATE.

Since you cannot use OUTPUT for any important data, Microsoft's Entity Framework uses the same workaround that I do:

Workaround #3 - Final - Do not use OUTPUT clause

In order to retrieve the after values, Entity Framework issues:

UPDATE [dbo].[BatchReports]
SET [IsProcessed] = @0
WHERE (([BatchReportGUID] = @1) AND ([RowVersion] = @2))

SELECT [RowVersion], [LastModifiedDate]
FROM [dbo].[BatchReports]
WHERE @@ROWCOUNT > 0 AND [BatchReportGUID] = @1

Don't use OUTPUT.

Yes it suffers from a race condition, but that's the best SQL Server can do.

What about INSERTs

Do what Entity Framework does:

SET NOCOUNT ON;

DECLARE @generated_keys table([CustomerID] int)

INSERT Customers (FirstName, LastName)
OUTPUT inserted.[CustomerID] INTO @generated_keys
VALUES ('Steve', 'Brown')

SELECT t.[CustomerID], t.[CustomerGuid], t.[RowVersion], t.[CreatedDate]
FROM @generated_keys AS g
   INNER JOIN Customers AS t
   ON g.[CustomerGUID] = t.[CustomerGUID]
WHERE @@ROWCOUNT > 0

Again, they use a SELECT statement to read the row, rather than placing any trust in the OUTPUT clause.

Thursday, June 10, 2021
 
Semirix
 
2

CASE is an expression - it returns a single scalar value (per row). It can't return a complex part of the parse tree of something else, like an ORDER BY clause of a SELECT statement.

It looks like you just need:

ORDER BY 
CASE WHEN TblList.PinRequestCount <> 0 THEN TblList.PinRequestCount END desc,
CASE WHEN TblList.HighCallAlertCount <> 0 THEN TblList.HighCallAlertCount END desc, 
Case WHEN TblList.HighAlertCount <> 0 THEN TblList.HighAlertCount END DESC,
CASE WHEN TblList.MediumCallAlertCount <> 0 THEN TblList.MediumCallAlertCount END DESC,
Case WHEN TblList.MediumAlertCount <> 0 THEN TblList.MediumAlertCount END DESC,
TblList.LastName ASC, TblList.FirstName ASC, TblList.MiddleName ASC

Or possibly:

ORDER BY 
CASE
   WHEN TblList.PinRequestCount <> 0 THEN TblList.PinRequestCount
   WHEN TblList.HighCallAlertCount <> 0 THEN TblList.HighCallAlertCount
   WHEN TblList.HighAlertCount <> 0 THEN TblList.HighAlertCount
   WHEN TblList.MediumCallAlertCount <> 0 THEN TblList.MediumCallAlertCount
   WHEN TblList.MediumAlertCount <> 0 THEN TblList.MediumAlertCount
END desc,
TblList.LastName ASC, TblList.FirstName ASC, TblList.MiddleName ASC

It's a little tricky to tell which of the above (or something else) is what you're looking for because you've a) not explained what actual sort order you're trying to achieve, and b) not supplied any sample data and expected results, from which we could attempt to deduce the actual sort order you're trying to achieve.


This may be the answer we're looking for:

ORDER BY 
CASE
   WHEN TblList.PinRequestCount <> 0 THEN 5
   WHEN TblList.HighCallAlertCount <> 0 THEN 4
   WHEN TblList.HighAlertCount <> 0 THEN 3
   WHEN TblList.MediumCallAlertCount <> 0 THEN 2
   WHEN TblList.MediumAlertCount <> 0 THEN 1
END desc,
CASE
   WHEN TblList.PinRequestCount <> 0 THEN TblList.PinRequestCount
   WHEN TblList.HighCallAlertCount <> 0 THEN TblList.HighCallAlertCount
   WHEN TblList.HighAlertCount <> 0 THEN TblList.HighAlertCount
   WHEN TblList.MediumCallAlertCount <> 0 THEN TblList.MediumCallAlertCount
   WHEN TblList.MediumAlertCount <> 0 THEN TblList.MediumAlertCount
END desc,
TblList.LastName ASC, TblList.FirstName ASC, TblList.MiddleName ASC
Thursday, June 10, 2021
 
3
select column1 from Table1
  where (@param is null and column2 is null)
     or (column2 = @param)
Thursday, July 29, 2021
 
VieStar
 
3

You have to use CASE Statement/Expression

Select * from Customer
WHERE  (I.IsClose=@ISClose OR @ISClose is NULL)  
AND    
    (C.FirstName like '%'+@ClientName+'%' or @ClientName is NULL )    
AND 
     CASE @Value
         WHEN 2 THEN (CASE I.RecurringCharge WHEN @Total or @Total is NULL) 
         WHEN 3 THEN (CASE WHEN I.RecurringCharge like 
                               '%'+cast(@Total as varchar(50))+'%' 
                     or @Total is NULL )
     END
Wednesday, August 4, 2021
 
Only authorized users can answer the question. Please sign in first, or register a free account.
Not the answer you're looking for? Browse other questions tagged :