Dynamic where Clause in SQL - tsql

I would like to be able to alter a where clause in a Stored Procedure based upon the value of a parameter passed to it.
E.G.
This is how I think it should work but I cannot get it quite right
Declare #param as int
set #param = 1
Select Productname
from product
where
case #param = 1 then productname = 1
else productname <> 1
end
I have been looking at Dynamic SQL etc?
Thanks in advance

Try this WHERE clause:
WHERE (#param = 1 AND productname = 1)
OR (#param <> 1 AND productname <> 1)
The parentheses are not strictly needed here because AND has higher precedence than OR but I've added them anyway for clarity.

Related

How to put a select into an integer with POSTGRESQL

I want to put this request (SELECT qte FROM table_stock where id_pro = cpt1) into an integer, like that i will be able to check if the product still exist (if quantity >0) so I us
SELECT qte
into quantite
FROM table_stock
where id_pro = cpt1;
More details in the PL/pgSQL reference
Try to avoid the loop with a single query like insert into table_result select... where quantity > 0;

Select case with different queries

in my current project I use a lot of stored procedures. In order to reduce the number of SPs I am thinking of putting several queries in one SQ, i. E.
enter code here#ArtQuery int = 0
/*
0 = SELECT
1 = INSERT
2 = UPDATE
3 = DELETE
*/
enter code hereAS
SET NOCOUNT ON;
SELECT
CASE
WHEN #ArtQuery = 0
--Select Statement
WHEN #ArtQuery = 1
--Insert Statement
Unfortunately that does not work. The select statement is accepted, the others aren't. Is that my mistake or isn't it possible having different queries in one SP?
I solved the problem by using IF clauses instead.

Compare 2 fields in where statement ORMLite

Is it possible to compare 2 fields from the table in where condition in ORMLite without using where().raw(statement, args)?
SQL query looks like
select
*
from
table
where
table.f1 = table.f2
try This ... i hope Its Work For You !!!
select (case when (table.f1 = table.f2 ) then 'EQUAL' else 'NOT_EQUAL' end) as one from table
OR
SELECT * FROM table WHERE f1 LIKE 'f2';
OR
SELECT * FROM table WHERE f1 = f2;
Don't know why I missed this last time. ORM Lite doc contains the answer:
ColumnArg object is designed to compare one column against another.
QueryBuilder<Table, String> queryBuilder = tableDao.queryBuilder();
queryBuilder.where().eq(Table.f1,
new ColumnArg(Table.f2));
List<Table> results = queryBuilder.query();

How can I query 'between' numeric data on a not numeric field?

I've got a query that I've just found in the database that is failing causing a report to fall over. The basic gist of the query:
Select *
From table
Where IsNull(myField, '') <> ''
And IsNumeric(myField) = 1
And Convert(int, myField) Between #StartRange And #EndRange
Now, myField doesn't contain numeric data in all the rows [it is of nvarchar type]... but this query was obviously designed such that it only cares about rows where the data in this field is numeric.
The problem with this is that T-SQL (near as I understand) doesn't shortcircuit the Where clause thus causing it to ditch out on records where the data is not numeric with the exception:
Msg 245, Level 16, State 1, Line 1
Conversion failed when converting the nvarchar value '/A' to data type int.
Short of dumping all the rows where myField is numeric into a temporary table and then querying that for rows where the field is in the specified range, what can I do that is optimal?
My first parse purely to attempt to analyse the returned data and see what was going on was:
Select *
From (
Select *
From table
Where IsNull(myField, '') <> ''
And IsNumeric(myField) = 1
) t0
Where Convert(int, myField) Between #StartRange And #EndRange
But I get the same error I did for the first query which I'm not sure I understand as I'm not converting any data that shouldn't be numeric at this point. The subquery should only have returned rows where myField contains numeric data.
Maybe I need my morning tea, but does this make sense to anyone? Another set of eyes would help.
Thanks in advance
IsNumeric only tells you that the string can be converted to one of the numeric types in SQL Server. It may be able to convert it to money, or to a float, but may not be able to convert it to an int.
Change your
IsNumeric(myField) = 1
to be:
not myField like '%[^0-9]%' and LEN(myField) < 9
(that is, you want myField to contain only digits, and fit in an int)
Edit examples:
select ISNUMERIC('.'),ISNUMERIC('£'),ISNUMERIC('1d9')
result:
----------- ----------- -----------
1 1 1
(1 row(s) affected)
You'd have to force SQL to evaluate the expressions in a certain order.
Here is one solution
Select *
From ( TOP 2000000000
Select *
From table
Where IsNumeric(myField) = 1
And IsNull(myField, '') <> ''
ORDER BY Key
) t0
Where Convert(int, myField) Between #StartRange And #EndRange
and another
Select *
From table
Where
CASE
WHEN IsNumeric(myField) = 1 And IsNull(myField, '') <> ''
THEN Convert(int, myField) ELSE #StartRange-1
END Between #StartRange And #EndRange
The first technique is "intermediate materialisation": it forces a sort on a working table.
The 2nd relies on CASE ORDER evaluation is guaranteed
Neither is pretty or whizzy
SQL is declarative: you tell the optimiser what you want, not how to do it. The tricks above force things to be done in a certain order.
Not sure if this helps you, but I did read somewhere that incorrect conversion using CONVERT will always generate error in SQL. So I think it would be better to use CASE in where clause to avoid having CONVERT to run on all rows
Use a CASE statement.
declare #StartRange int
declare #EndRange int
set #StartRange = 1
set #EndRange = 3
select *
from TestData
WHERE Case WHEN ISNUMERIC(Value) = 0 THEN 0
WHEN Value IS NULL THEN 0
WHEN Value = '' THEN 0
WHEN CONVERT(int, Value) BETWEEN #StartRange AND #EndRange THEN 1
END = 1

Paging in Entity Framework

In Entity Framework, using LINQ to Entities, database paging is usually done in following manner:
int totalRecords = EntityContext.Context.UserSet.Count;
var list = EntityContext.Context.UserSet
.Skip(startingRecordNumber)
.Take(pageSize)
.ToList();
This results in TWO database calls.
Please tell, how to reduce it to ONE database call.
Thank You.
Whats wrong with two calls? They are small and quick queries. Databases are designed to support lots of small queries.
A developing a complex solution to do one query for paging isn't going give you much pay off.
Using Esql and mapping a stored procedure to an entity can solve the problem.
SP will return totalRows as output parameter and current page as resultset.
CREATE PROCEDURE getPagedList(
#PageNumber int,
#PageSize int,
#totalRecordCount int OUTPUT
AS
//Return paged records
Please advise.
Thank You.
Hmmm... the actual call that uses paging is the second one - that's a single call.
The second call is to determine the total number of rows - that's quite a different operation, and I am not aware of any way you could combine those two distinct operations into a single database call with the Entity Framework.
Question is: do you really need the total number of rows? What for? Is that worth a second database call or not?
Another option you would have is to use the EntityObjectSource (in ASP.NET) and then bind this to e.g. a GridView, and enable AllowPaging and AllowSorting etc. on the GridView, and let the ASP.NET runtime handle all the nitty-gritty work of retrieving the appropriate data page and displaying it.
Marc
ALTER proc [dbo].[GetNames]
#lastRow bigint,
#pageSize bigint,
#totalRowCount bigint output
as
begin
select #totalRowCount = count(*) from _firstNames, _lastNames
select
FirstName,
LastName,
RowNumber
from
(
select
fn.[FirstName] as FirstName,
ln.[Name] as LastName,
row_number() over( order by FirstName ) as RowNumber
from
_firstNames fn, _lastNames ln
) as data
where
RowNumber between ( #lastRow + 1 ) and ( #lastRow + #pageSize )
end
There is no way to get this into one call, but this works fast enough.
This queries are too small for DBManager and I can not understand why you want to do this, anyway for reduce it to ONE database call use this:
var list = EntityContext.Context.UserSet
.Skip(startingRecordNumber)
.Take(pageSize)
.ToList();
int totalRecords = list.Count;
Suppose you want to get the details of Page 2 with a pagesize=4
int page =2;
int pagesize=4;
var pagedDetails= Categories.Skip(pagesize*(page-1)).Take(pagesize)
.Join(Categories.Select(item=>new {item.CategoryID,Total = Categories.Count()}),x=>x.CategoryID,y=>y.CategoryID,(x,y)=>new {Category = x,TotalRows=y.Total});
The Output will have all details of Category and TotalRows.
One DB call.
Generated SQL
-- Region Parameters
DECLARE #p0 Int = 2
DECLARE #p1 Int = 4
-- EndRegion
SELECT [t2].[CategoryID], [t2].[CategoryName], [t2].[Description], [t2].[Picture], [t5].[value] AS [TotalRows]
FROM (
SELECT [t1].[CategoryID], [t1].[CategoryName], [t1].[Description], [t1].[Picture], [t1].[ROW_NUMBER]
FROM (
SELECT ROW_NUMBER() OVER (ORDER BY [t0].[CategoryID], [t0].[CategoryName]) AS [ROW_NUMBER], [t0].[CategoryID], [t0].[CategoryName], [t0].[Description], [t0].[Picture]
FROM [Categories] AS [t0]
) AS [t1]
WHERE [t1].[ROW_NUMBER] BETWEEN #p0 + 1 AND #p0 + #p1
) AS [t2]
INNER JOIN (
SELECT [t3].[CategoryID], (
SELECT COUNT(*)
FROM [Categories] AS [t4]
) AS [value]
FROM [Categories] AS [t3]
) AS [t5] ON [t2].[CategoryID] = [t5].[CategoryID]
ORDER BY [t2].[ROW_NUMBER]