July 11, 2008 at 4:58 pm
antonio.collins (7/10/2008)
before i write some awful case statements or multiple UDFs, is there any direct way to determine if any values in a list are negative?coalesce_negative( 1, 1, 1,-1, 1,-1,-1,-1, 1) would return -1.
i can't just multiply the values together since -1 * -1 * 1 * 1 = 1. sometimes i need to coalesce 4 values, sometimes 5, sometimes 15 and since UDFs don't allow optional parameters, i'd wind up needing 3 UDFs (and a new UDF if 12 values need to be checked.
the logic has to be used as part of a select so a stored proc is not suitable.
This could be a very simple UDF... but I need to know... where does the list come from and could it be passed to a function as a VARCHAR datatype?
--Jeff Moden
Change is inevitable... Change for the better is not.
July 11, 2008 at 8:35 pm
The canonical way to do this is to OR the values to gether and then test the Negative bit (or just test the final result for negative). Unfortunately, there is no aggregate OR function built-in to SQL, and as we all know, writing your own in CLR is not nearly as fast.
[font="Times New Roman"]-- RBarryYoung[/font], [font="Times New Roman"] (302)375-0451[/font] blog: MovingSQL.com, Twitter: @RBarryYoung[font="Arial Black"]
Proactive Performance Solutions, Inc. [/font][font="Verdana"] "Performance is our middle name."[/font]
July 12, 2008 at 9:26 am
rbarryyoung (7/11/2008)
The canonical way to do this is to OR the values to gether and then test the Negative bit (or just test the final result for negative). Unfortunately, there is no aggregate OR function built-in to SQL, and as we all know, writing your own in CLR is not nearly as fast.
But it is easy in T-SQL... that's why I was asking what the real form of the passed parameters were... makes a difference in how I'll write the split that will drive it all.
--Jeff Moden
Change is inevitable... Change for the better is not.
July 14, 2008 at 7:37 am
Since the original example is using a string-split function to break it into rows, I'm pretty sure that's the desired input. But I think he already has what he needs on this one.
- Gus "GSquared", RSVP, OODA, MAP, NMVP, FAQ, SAT, SQL, DNA, RNA, UOI, IOU, AM, PM, AD, BC, BCE, USA, UN, CF, ROFL, LOL, ETC
Property of The Thread
"Nobody knows the age of the human race, but everyone agrees it's old enough to know better." - Anon
July 14, 2008 at 7:49 am
GSquared (7/14/2008)
Since the original example is using a string-split function to break it into rows, I'm pretty sure that's the desired input. But I think he already has what he needs on this one.
no, the values are float columns from the current row. stringing them together was a thought but i wanted something better.
select
...
case when 0 > ANY (select B.val_01 union select B.val_02 ... union select B.val_15) then -1 else 0 end as negVal1,
case when 0 > ANY (select B.another_01 union select B.another_02 union select B.another_03) then -1 else 0 end as negVal2,
...
the any subselect suggested by k.simmons has hardly any impact on performance and is straightforward to understand and maintain.
July 14, 2008 at 8:34 am
This looks like fun, so I'm chipping in...
declare @t table (id int identity(1, 1), a1 int, a2 int, a3 int, a4 int, a5 int, a6 int, a7 int, a8 int, a9 int)
insert @t
select 1, 1, 1, -1, 1, -1, -1, -1, 1
union all select 1, 1, 1, 1, 1, 1, 1, 1, 1
union all select 1, 1, 1, 1, 1, -1, 1, 1, 1
union all select 1, 2, 3, 4, 5, 6, 7, 8, 9
union all select 1, -2, 3, -4, 5, -6, 7, -8, 9
; with b as (
select id, case when sum(v) = sum(abs(v)) then 0 else 1 end as HasNegatives
from @t unpivot (v for c in ([a1], [a2], [a3], [a4], [a5], [a6], [a7], [a8], [a9])) as x
group by id)
select a.*, b.HasNegatives from @t a inner join b on a.id = b.id
/*
id a1 a2 a3 a4 a5 a6 a7 a8 a9 HasNegatives
------ ------ ------ ------ ------ ------ ------ ------ ------ ------ ------------
1 1 1 1 -1 1 -1 -1 -1 1 1
2 1 1 1 1 1 1 1 1 1 0
3 1 1 1 1 1 -1 1 1 1 1
4 1 2 3 4 5 6 7 8 9 0
5 1 -2 3 -4 5 -6 7 -8 9 1
*/
Ryan Randall
Solutions are easy. Understanding the problem, now, that's the hard part.
July 14, 2008 at 8:48 am
If it's columns in a table, then you can use Unpivot and either the sum() - sum(abs()) calculation, or the 0 > Any function. Either will work.
Edit: And, had I been paying attention, I would have realized someone had beaten me to the punch on Unpivot.
- Gus "GSquared", RSVP, OODA, MAP, NMVP, FAQ, SAT, SQL, DNA, RNA, UOI, IOU, AM, PM, AD, BC, BCE, USA, UN, CF, ROFL, LOL, ETC
Property of The Thread
"Nobody knows the age of the human race, but everyone agrees it's old enough to know better." - Anon
July 14, 2008 at 9:22 am
RyanRandall (7/14/2008)
This looks like fun, so I'm chipping in...
declare @t table (id int identity(1, 1), a1 int, a2 int, a3 int, a4 int, a5 int, a6 int, a7 int, a8 int, a9 int)
insert @t
select 1, 1, 1, -1, 1, -1, -1, -1, 1
union all select 1, 1, 1, 1, 1, 1, 1, 1, 1
union all select 1, 1, 1, 1, 1, -1, 1, 1, 1
union all select 1, 2, 3, 4, 5, 6, 7, 8, 9
union all select 1, -2, 3, -4, 5, -6, 7, -8, 9
; with b as (
select id, case when sum(v) = sum(abs(v)) then 0 else 1 end as HasNegatives
from @t unpivot (v for c in ([a1], [a2], [a3], [a4], [a5], [a6], [a7], [a8], [a9])) as x
group by id)
select a.*, b.HasNegatives from @t a inner join b on a.id = b.id
/*
id a1 a2 a3 a4 a5 a6 a7 a8 a9 HasNegatives
------ ------ ------ ------ ------ ------ ------ ------ ------ ------ ------------
1 1 1 1 -1 1 -1 -1 -1 1 1
2 1 1 1 1 1 1 1 1 1 0
3 1 1 1 1 1 -1 1 1 1 1
4 1 2 3 4 5 6 7 8 9 0
5 1 -2 3 -4 5 -6 7 -8 9 1
*/
Slightly simpler (I must be really bored today...)
select id, sign(sum(abs(v)-v)) as HasNegatives
...
____________________________________________________
Deja View - The strange feeling that somewhere, sometime you've optimised this query before
How to get the best help on a forum
http://www.sqlservercentral.com/articles/Best+Practices/61537July 14, 2008 at 11:27 am
Sign doesn't get him precisely what he's looking for, but it could probably be used. And it does reduce even further the typing required. 🙂
- Gus "GSquared", RSVP, OODA, MAP, NMVP, FAQ, SAT, SQL, DNA, RNA, UOI, IOU, AM, PM, AD, BC, BCE, USA, UN, CF, ROFL, LOL, ETC
Property of The Thread
"Nobody knows the age of the human race, but everyone agrees it's old enough to know better." - Anon
July 14, 2008 at 2:17 pm
Just curious... the SIGN method with the subtraction from the ABS seems to work just fine as a negative number detector...
DECLARE @v-2 INT
SET @v-2 = -10
SELECT ABS(@V)-@V, SIGN(ABS(@V)-@V) AS IsNegative
SET @v-2 = 10
SELECT ABS(@V)-@V, SIGN(ABS(@V)-@V) AS IsNegative
SET @v-2 = 0
SELECT ABS(@V)-@V, SIGN(ABS(@V)-@V) AS IsNegative
--Jeff Moden
Change is inevitable... Change for the better is not.
July 14, 2008 at 2:21 pm
He's looking for a binary. Otherwise Sign would work. Possible that he can change his requirement, of course.
- Gus "GSquared", RSVP, OODA, MAP, NMVP, FAQ, SAT, SQL, DNA, RNA, UOI, IOU, AM, PM, AD, BC, BCE, USA, UN, CF, ROFL, LOL, ETC
Property of The Thread
"Nobody knows the age of the human race, but everyone agrees it's old enough to know better." - Anon
July 14, 2008 at 2:23 pm
Ummmm, so convert the result to a Bit datatype... all that is being returned are 1's and 0's... no -1's...
--Jeff Moden
Change is inevitable... Change for the better is not.
July 14, 2008 at 2:33 pm
True.
- Gus "GSquared", RSVP, OODA, MAP, NMVP, FAQ, SAT, SQL, DNA, RNA, UOI, IOU, AM, PM, AD, BC, BCE, USA, UN, CF, ROFL, LOL, ETC
Property of The Thread
"Nobody knows the age of the human race, but everyone agrees it's old enough to know better." - Anon
Viewing 13 posts - 16 through 27 (of 27 total)
You must be logged in to reply to this topic. Login to reply