Please start any new threads on our new
site at https://forums.sqlteam.com. We've got lots of great SQL Server
experts to answer whatever question you can come up with.
| Author |
Topic |
|
HarryMann
Starting Member
33 Posts |
Posted - 2002-03-19 : 17:27:58
|
| I love the power of Case statements and whilst in the past have found syntactical wrinkles have usually found a way through the (very badly documented) variety of constructs. Now, there are 2 interrelated problems:1) Sorting a resultset based upon an input parameter will always give an annoying (& I'm convinced parsing bug) parsetime message that one 'cannot use a numeric col posn argument' to order a resultset, EVEN when I declare my input arg as varchar and pass in the actual column name.2) To avoid this (bug, feature or over enthusiastic parser) I have previously used a Case statement in the Order By clause. It has worked, passing in a column number or name:However, now, with the exact same syntax, I can get it to parse and compile BUT when run, I get a silly error (unless the sort column is of a numeric data type) which error in Query Analyser says that cannot coerce a varchar to a float or int, Line Number:= the line number of the first Select statement line, which has nothing at all to do with the problem, since removing the Order By clauses removes this error.The TSQL Stored proc is: (and this construct works fine elsewhere, is actually in production):CREATE PROCEDURE sp_ETD_ViewMarketPlace_OTV@intOTV int ASSelect sd.DSASubDeclarationNo As 'DSA Ref.',sd.DecQuantity as 'Qty.',c.CommodityName as 'Cmdty.',cc.CommodityClassName as 'Cmdty. Class',dt.DisposalMethodName as 'Disp. Method'from tSubDeclaration sdInner Join mtQuantityType q on sd.QuantityTypeID = q.QuantityTypeID Inner Join tCommodity c On sd.CommodityID = c.CommodityIDInner Join tCommodityClass cc On c.CommodityClassID = cc.CommodityClassIDInner Join mtDisposalMethod dt On sd.DisposalMethodID = dt.DisposalMethodIDWhere IsDate(sd.Whensold) = 0 and sd.DSASubDeclarationNo Like '200%'Order By Case When (1=@intOTV) Then sd.DSASubDeclarationNo When (2=@intOTV) Then sd.DecQuantity When (3=@intOTV) Then c.CommodityName When (4=@intOTV) Then cc.CommodityClassName When (5=@intOTV) Then dt.DisposalMethodName Else sd.DSASubDeclarationNoEND --This Order By Case When Condition Then OrderBy ColumnNameDOES work, but why not hereAny help or suggestions very gratefully received - Thanks |
|
|
HarryMann
Starting Member
33 Posts |
Posted - 2002-03-19 : 20:24:33
|
| Clarification:That all sounded a bit confused! Simply put, Garth illustrates an example of using 'Dynamic Order By' on 1/22/2001 on this site.It works, but he only sorts on numeric fields, whilst my query attempts to sort dynamically (using an Onput argument) on varchar fields. I get 'Cannot convert varchar to float' line xxxx where linexxx i the first line of the Select Statement.This is crazy, as I have another sp running which does this identically and it does sort dynamically and correctly, but on a different table. Any help out there, can I msg Garth in person? |
 |
|
|
robvolk
Most Valuable Yak
15732 Posts |
Posted - 2002-03-19 : 20:28:35
|
| In order for the parser to process the ORDER BY correctly, all of the CASE expressions must have the same datatype. If you mix numeric columns with char/varchar columns, you must convert the numeric values to char or varchar in the ORDER BY clause. This also applies to datetime values. |
 |
|
|
HarryMann
Starting Member
33 Posts |
Posted - 2002-03-19 : 20:50:00
|
| Thanks RobVolk,Really nice to have you folks out there, listening out, fraid I can't help out with many at the moment, but learning all the time .A bit of a restriction but spose I can see why this is; that'll be it, as theres just ONE numeric column, a float - Mmmmm what a nuisance, so how else can we sort dynamically?CSmith |
 |
|
|
robvolk
Most Valuable Yak
15732 Posts |
Posted - 2002-03-19 : 20:59:22
|
| It's no big deal to change the CASE statement a little:Order By Case When (1=@intOTV) Then CONVERT(varchar(10), sd.DSASubDeclarationNo)When (2=@intOTV) Then CONVERT(varchar(10), sd.DecQuantity)...I think the STR() function might be better than CONVERT() for number conversion though, because it allows for more precise control over the value returned. FYII usually move the CASE expression into the SELECT list, then give that column an alias. You can then ORDER BY the alias for the column, not the CASE expression:Select sd.DSASubDeclarationNo As 'DSA Ref.',sd.DecQuantity as 'Qty.',c.CommodityName as 'Cmdty.',cc.CommodityClassName as 'Cmdty. Class',dt.DisposalMethodName as 'Disp. Method',Case When (1=@intOTV) Then sd.DSASubDeclarationNoWhen (2=@intOTV) Then sd.DecQuantityWhen (3=@intOTV) Then c.CommodityNameWhen (4=@intOTV) Then cc.CommodityClassNameWhen (5=@intOTV) Then dt.DisposalMethodNameElse sd.DSASubDeclarationNoEND AS SortColfrom tSubDeclaration sdInner Join mtQuantityType q on sd.QuantityTypeID = q.QuantityTypeID Inner Join tCommodity c On sd.CommodityID = c.CommodityIDInner Join tCommodityClass cc On c.CommodityClassID = cc.CommodityClassIDInner Join mtDisposalMethod dt On sd.DisposalMethodID = dt.DisposalMethodIDWhere IsDate(sd.Whensold) = 0 and sd.DSASubDeclarationNo Like '200%'Order By SortColThe only problem is that you have an extra column outputted in the SELECT list. It's a trade-off.The only way to completely avoid these workarounds, without using dynamic SQL, is to create an IF...THEN block for each ORDER BY option, then put the entire SQL statement with the proper ORDER BY within each block. Yeah, it duplicates a lot of code, but it also optimizes perfectly for each ORDER BY condition, which none of these other methods can do. |
 |
|
|
joldham
Wiseass Yak Posting Master
300 Posts |
Posted - 2002-03-19 : 22:42:14
|
| I am not 100% sure on this and maybe someone else here can shed some further light on this, but I think you may be getting the conversion error because in your case statement, when you compare:When (1=@intOTV) Then sd.DSASubDeclarationNoWhen (2=@intOTV) Then sd.DecQuantityWhen (3=@intOTV) Then c.CommodityNameWhen (4=@intOTV) Then cc.CommodityClassNameWhen (5=@intOTV) Then dt.DisposalMethodNameI was under the assumption that the 1 in the select statement would refer to the column for comparison. In other words, SQL interprets this statement as the following:When (sd.DSASubDeclarationNo=@intOTV) Then sd.DSASubDeclarationNoWhen (sd.DecQuantity=@intOTV) Then sd.DecQuantityWhen (c.CommodityName=@intOTV) Then c.CommodityNameWhen (cc.CommodityClassName=@intOTV) Then cc.CommodityClassNameWhen (dt.DisposalMethodName=@intOTV) Then dt.DisposalMethodNameIf this truly is the case, I would think that you could change you Case statement to the following:When (@intOTV=1) Then sd.DSASubDeclarationNoWhen (@intOTV=2) Then sd.DecQuantityWhen (@intOTV=3) Then c.CommodityNameWhen (@intOTV=4) Then cc.CommodityClassNameWhen (@intOTV=5) Then dt.DisposalMethodNameI hope this helps or that someone can confirm what I think is correct.Keep me posted on if this solves the problem.Jeremy |
 |
|
|
|
|
|
|
|