Showing posts with label statements. Show all posts
Showing posts with label statements. Show all posts

Friday, March 30, 2012

How to makw Conditional Statements in SELECT

I'm trying to code a storedprocedure which looks for a product in a table. It takes one Paramater. Value may be 1 or 2 or 3.

CREATE PROCEDURE [dbo].[procSearchProduct]

@.PromoPrm int

AS

BEGIN

SELECT *

FROM tblProduct AS P

WHERE ?

END

END

--

if @.PromoPrm = 1 then where statement will be like this one: WHERE P.Promo = 'True'

else if @.PromoPrm = 2 then where statement will be like this one: WHERE P.Promo = 'False'

else if @.PromoPrm = 3 then where statement will be like this one: WHERE P.Promo = 'False' OR P.Promo = 'True'

Hope i am clear on my problem. Let me know if you don't understand it. Waiting for a solution.

Happy Coding...

One method is to us if/else:

IF @.PromoPrm = 1

select * from tblProduct p

where p.promo = 'True'

else if @.promo = 2

select * from tblProduct p

where p.promo = 'False'

else if @.promoPrm = 3

select * from tblProduct p

where p.promo = 'False'

or p.promo = 'True'

If your PROMO column can only have the values of TRUE or FALSE you can leave out the WHERE condition on the IF @.promoPrm = 3 portion.

The next comment is that you should avoid using the SELECT * syntax in stored procedures. Give a look to this post concerning this issue:

http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=1108698&SiteID=1

Use of the 'SELECT *' syntax in stored procedures can leave behind "land mines" that go off at a later date and time when changes are made to the columns of the source table.

Another approach to the problem is something like:

select * from tblProduct p

where @.promoPrm = 1

and p.promo = 'TRUE'

or @.promoPrm = 2

and p.promo = 'FALSE'

or @.promoPrm = 3

and ( p.promo = 'TRUE' OR

p.promo = 'FALSE'

)

|||

Here's a version using dynamic SQL.

declare @.sql varchar(max);

declare @.where varchar(max);

set @.where = case @.promoprm

when 1 Then'WHERE Promo = ''True'''

when 2 Then 'WHERE Promo = ''False'''

when 3 Then 'WHERE Promo = ''True'' OR Promo = ''False'''

end;

set @.sql = 'SELECT * FROM tblProducts ' + @.where;

exec(@.sql);

Jamie

|||

Yeap it is a solution but i gave little part of the code. Trying to make a seach form in asp.net . And u know this kind of page sends many parameters to sql. I can't make all combination in sql. I mean what about if this stored procedure takes 5 Parameters like @.PromoPrm . Point this problem is i have to write a code which makes decision on WHERE part. May be like this one :

SELECT *

FROM tblProduct AS P

WHERE case when P.Promo = 1 then P.Promo = 'True' else P.Promo = 'False'

This query is wrong but i hope u got the point?

|||

Beware using any dynamic SQL, especially in a web environment. You don't want to leave yourself open to code injection.

Jamie

|||

To simplyfy this,

Code Snippet

select * from tblProduct p

where @.promoPrm & 1 = 1 and p.promo = 'TRUE'

or @.promoPrm & 2 = 2 and p.promo = 'FALSE'

|||

Give a look to the "dynamic search" article by MVP Erland Sommarskog:

http://www.sommarskog.se/dyn-search.html

Also, it will help if you finish describing your problem rather giving information in portions.

|||

JHunter i think your solution is good but sql injection is important in this stiuation. If i use your code sample than i need to check the paramateres in my code but it is very very difficult because it takes it from query string. Is there any solution to this problem?

Kent thanks for post. Also thanks for link that u gave.

|||

ManiD wrote:

To simplyfy this,

Code Snippet

select * from tblProduct p

where @.promoPrm & 1 = 1 and p.promo = 'TRUE'

or @.promoPrm & 2 = 2 and p.promo = 'FALSE'

ManiD i think your solution is the best. What about the performance. Because i will use this on 5 different paramaters.

|||

If you are only passing an integer to the stored proc, leaving the proc to decide how the where clause is constructed, you'll be okay. Problems come when you start passing strings that contain SQL as parameters .

The simplest check you can do is make sure the parameter contains only "expected" values.

Erlands (as previously posted) page provides some of the best content relating to dynamic SQL.

Jamie

|||How many possible values are there for the PROMO column? If it is but a handful this will probably scan and not seek because of the cardinalities.|||

Ok here is the problem again: I'm trying to make a search form. Form runs a stored procedure call it procSearchProduct. This stored procedure takes 6 parameters.

@.CityPrm varchar(50), --takes the name of city

@.HasPromotionPrm int, -- takes onl 3 value. 1,2 or 3. 1=True , 2=Fale , 3=True OR False

@.HasDescriptionPrm, int,-- takes onl 3 value. 1,2 or 3. 1=True , 2=Fale , 3=True OR False

@.HasImagePrm int,-- takes onl 3 value. 1,2 or 3. 1=True , 2=Fale , 3=True OR False

@.StateofShopPrm varchar(50), -- takes the name of the state

@.ShopClosedOpenedPrm int -- takes onl 3 value. 1,2 or 3. 1=True , 2=Fale , 3=True OR False

what i am trying to do is select values from table. You know the rest. Sory i couldn't paste the whole code because i wrting it on dofferent language so it will not help.

|||

I'd avoid passing CityPrm and StateofShopPrm as varchars. Instead, create lookup tables for the city and state with a numeric primary key.

Populate any dropdown menus from these lookups, but capture the primary key (ID) of the selected value - not the name. This numeric ID can be passed to the stored procedure.

If you've not normalised your main table, you can use the primary key to lookup the textual value for the lookup.

Jamie

|||Also, on these VARCHAR fields, are you doing = searches or LIKE searches?|||Another point , user selects the option "WHOLE WORD" or "SOME OF THEM" in drop down for search condition on City but it will mess the problem much more. Assume that i make = search. And I cant take the State in to a dropdownlist. May be a solution but not for me.

Wednesday, March 28, 2012

How to make sure no other table writes happen between 2 SQL statements ?

Ok, here is my situation....

When someone navigates to a user's profile page on my site, I present them with a slideshow of the user's photos using the AJAX slideshow extender. I obtain the querystring value in the URL (to determine which user's page I'm on) and feed that into a webservice via a context value where an array of photos is created for the slideshow. Now, in order to create the array's size, I do a COUNT of all of that specific user's photos. Then, I run another SQL statement to obtain the path of those photos in the file system. However, during the time of that first SQL query's execution (the COUNT statement) to the time of the second SQL query (getting the paths of the photos), the owner of that profile may upload or delete a photo from his profile. I understand this would be a very rare occurrence since SQL statements 1 and 2 will be executed within milliseconds of each other, but it is still possible I suppose. When this happens, when I try to populate the array, either the array will be too small or too large. I'm using SqlDataReader for this as it seems to be less memory and resource intensive than datasets, but I could be wrong since I'm a relative beginner and newbie.Wink This is what I have in my vb file for the webservice....

PublicFunction GetSlides(ByVal contextKeyAsString)As AjaxControlToolkit.Slide()
Dim dbConnectionAsNew SqlConnection("string for the data source, etc.")

Try
dbConnection.Open()

Dim memberId =CInt(contextKey)
Dim photoCountLookupCmdAsNew SqlCommand _
("SELECT COUNT(*) FROM Photo WHERE memberId = " & memberId, dbConnection)
Dim thisReaderAs SqlDataReader = photoCountLookupCmd.ExecuteReader()

Dim photoCountAsInteger
While (thisReader.Read())
photoCount = thisReader.GetInt32(0)
EndWhile
thisReader.Close()

Dim MySlides(photoCount - 1)As AjaxControlToolkit.Slide

Dim photoLookupCmdAsNew SqlCommand _
("SELECT fullPath FROM Photo WHERE memberId = " & memberId, dbConnection)
thisReader = photoLookupCmd.ExecuteReader()

Dim iAsInteger
For i = 0To 2
thisReader.Read()
Dim photoUrlAsString = thisReader.GetString(0)
MySlides(i) =New AjaxControlToolkit.Slide(photoUrl,"","")
Next i
thisReader.Close()

Return MySlides

Catch exAs SqlException

Finally
dbConnection.Close()

EndTry

EndFunction

I'm trying to use the most efficient method to interact with the database since I don't have unlimited hardware and there may be moderate traffic on the site. Is SqlDataReader the way to go or do I use something else? If I do use SqlDataReader, can someone show me how I can run those 2 SQL statements in best practice? Would I have to somehow lock writing to that table when I start the first SQL statement, then release the lock after I execute the second SQL statement? What's the best practice in this kind of scenario.

Thanks in advance.Smile

Hello S2KDriver,

Why don't you use a SqlDataAdapter and fill a DataTable with your second SELECT statement (e.g. the photoLookupCommand). You can use the rowcount property to get the number of rows retrieved.

In this scenario you still have the chance that when Slides are added to the AjaxControlToolkit, the photo is deleted and not available.

|||

Hi jeroenm,

Yes, now that I think about it, you're right. Since the photo's filepath is contained in the database and not the photo itself, there can be more or less photos by the time the aspx page receives the array of photo filepaths.

Maybe this is an ignorant and a beginner question, but if the dataset doesn't solve this problem of making sure things are in sync, what is its benefit over the datareader? The only time I've used the dataset is when implementing custom paging with datalists (since you can't page forwards AND backwards with a datareader). In all other instances, I've used the datareader and then I'd always make sure to close the reader right after each reading. I'm trying to be as stingy as possible in terms of resource utilization... is my approach wrong?

And also, to the issue at hand, I guess the only way to keep things in sync, is to somehow lock writing to the Photo table right before I execute my first SQL statement (to prevent the owner of the profile from uploading or deleting his photos during those few milliseconds), then release the write lock after I return the array of photo filepaths back to the requesting aspx page. Am I correct? And if so, how would I do this?

Thanks.

|||

The dataset was my suggestion to get ride of the first select statement. In your situation a datareader gives probably less resource utilization.

Maybe you can use the following scenario:

- open a transaction with the appropriate isolation level.

- update photo records with the matching memberid. (locking the set of records, you want to read locked).

- you will get the number of records updated by the command in return (given you the count).

- select the rows with the datareader and process the result set.

- rollback the transaction (releasing the lock).

I don't know when the AjaxControlToolkit reads the photo's. But if they are read just before showed to the user, you still have a synchronization issue.

Monday, March 19, 2012

How to log select into/bulk copy transactions

Is there a way to be able to use select into and/or bulk copy statements AND have them logged into the transaction log? If I uncheck select into/bulk copy, these statements cannot be performed. If I leave them checked, the operations are not logged, making my transactions logs invalid.

EdBuilk copy operation are specially designed to be NONLOGGED. Since you have got operations that not looged in tranlog, there is no way to get db in consistant state using this tranlog. Thats why you need to perform full db backup.

In SQL2k u dont need perform full backup after builk ops anymore since they are logged thru BCM pages.

HTH,
OBRP