Hello all :) I'm strugglind to come up with the right SQL syntax in Oracle 10g. I would like to come up with something like this:
SELECT
LAST_VALUE FIELD_INFO OVER(ORDER BY FIELD_1 IS NULL, FIELD_2, FIELD_1)
FROM TABLE_1
FIELD_1 IS NULL raising a syntax error.
How would you do it?
NULLs First
This expression is a compact Oracle syntax to return 0 for Nulls and 1 for non-Nulls
Order by NVL2(FIELD_1,1,0), ...
Or you could use a case statement:
Order by Case when FIELD_1 is null then 0 else 1 end, ...
NULLs Last
Order by NVL2(FIELD_1,0,1)
Order by Case when FIELD_1 is null then 1 else 0 end, ...
There's possibly a fractional optimisation in this method:
Order by Case when FIELD_1 is null then null else 0 end nulls last, ...
... through requiring slightly less sort area.
I think you should make a compound field and sort by it
COALESCE(FIELD_1,'[lots of spaces to ensure they go first]')||FIELD_2
But it would really help if you post 10-20 example records to show exactly, what you want to achieve.
Related
Just wonder how conditional statements work behind the scene.
I am checking if multiple fields are all NULL.
-- OR: if there is any NOT NULL value
CASE
WHEN field_1 IS NOT NULL OR field_2 IS NOT NULL
THEN 1 ELSE 0
END
-- AND: if all values are null
CASE
WHEN field_1 IS NULL AND field_2 IS NULL
THEN 1 ELSE 1
END
Just wonder if it will be faster if I use OR rather than AND, because if condition 1 returns True then other conditions will not be evaluated?
Or it will be the same because all conditions are evaluated independently?
Do all SQL engines work in the same way on this matter? I'm using Teradata
Sorry if this a duplicate, but i haven't found one. Why can't i use my column alias defined in the SELECT from the ORDER BY when i use CASE?
Consider this simple query:
SELECT NewValue=CASE WHEN Value IS NULL THEN '<Null-Value>' ELSE Value END
FROM dbo.TableA
ORDER BY CASE WHEN NewValue='<Null-Value>' THEN 1 ELSE 0 END
The result is an error:
Invalid column name 'NewValue'
Here's a sql-fiddle. (Replace the ORDER BY NewValue with the CASE WHEN... that´'s commented out)
I know i can use ORDER BY CASE WHEN Value IS NULL THEN 1 ELSE 0 END like here in this case but actually the query is more complex and i want to keep it as readable as possible. Do i have to use a sub-query or CTE instead, if so why is that so?
Update as Mikael Eriksson has commented any expression in combination with an alias is not allowed. So even this (pointless query) fails for the same reason:
SELECT '' As Empty
FROM dbo.TableA
ORDER BY Empty + ''
Result:
Invalid column name 'Empty'.
So an alias is allowed in an ORDER BY and also an expression but not both. Why, is it too difficult to implement? Since i'm mainly a programmer i think of aliases as variables which could simple be used in an expression.
This has to do with how a SQL dbms resolves ambiguous names.
I haven't yet tracked down this behavior in the SQL standards, but it seems to be consistent across platforms. Here's what's happening.
create table test (
col_1 integer,
col_2 integer
);
insert into test (col_1, col_2) values
(1, 3),
(2, 2),
(3, 1);
Alias "col_1" as "col_2", and use the alias in the ORDER BY clause. The dbms resolves "col_2" in the ORDER BY as an alias for "col_1", and sorts by the values in "test"."col_1".
select col_1 as col_2
from test
order by col_2;
col_2
--
1
2
3
Again, alias "col_1" as "col_2", but use an expression in the ORDER BY clause. The dbms resolves "col_2" not as an alias for "col_1", but as the column "test"."col_2". It sorts by the values in "test"."col_2".
select col_1 as col_2
from test
order by (col_2 || '');
col_2
--
3
2
1
So in your case, your query fails because the dbms wants to resolve "NewValue" in the expression as a column name in a base table. But it's not; it's a column alias.
PostgreSQL
This behavior is documented in PostgreSQL in the section Sorting Rows. Their stated rationale is to reduce ambiguity.
Note that an output column name has to stand alone, that is, it cannot be used in an expression — for example, this is not correct:
SELECT a + b AS sum, c FROM table1 ORDER BY sum + c; -- wrong
This restriction is made to reduce ambiguity. There is still ambiguity if an ORDER BY item is a simple name that could match either an output column name or a column from the table expression. The output column is used in such cases. This would only cause confusion if you use AS to rename an output column to match some other table column's name.
Documentation error in SQL Server 2008
A slightly different issue with respect to aliases in the ORDER BY clause.
If column names are aliased in the SELECT list, only the alias name can be used in the ORDER BY clause.
Unless I'm insufficiently caffeinated, that's not true at all. This statement sorts by "test"."col_1" in both SQL Server 2008 and SQL Server 2012.
select col_1 as col_2
from test
order by col_1;
It seems this limitation is related to another limitation in which "column aliases can't be referenced in same SELECT list". For example, this query:
SELECT Col1 AS ColAlias1 FROM T ORDER BY ColAlias1
Can be translated to:
SELECT Col1 AS ColAlias1 FROM T ORDER BY 1
Which is a legal query. But this query:
SELECT Col1 AS ColAlias1 FROM T ORDER BY ColAlias1 + ' '
Should be translated to:
SELECT Col1 AS ColAlias1, ColAlias1 + ' ' FROM T ORDER BY 2
Which will raise the error:
Unknown column 'ColAlias1' in 'field list'
And finally it seems these are because of SQL standard behaviours not an impossibility in implementation.
More info at: Here
Note: The last query can be executed by MS Access without error but will raise the mentioned error with SQL Server.
You could try something like:
select NewValue from (
SELECT (CASE WHEN Value IS NULL THEN '<Null-Value>' ELSE Value END ) as NewValue,
( CASE WHEN NewValue='<Null-Value>' THEN 1 ELSE 0 END) as ValOrder
FROM dbo.TableA
GROUP BY Value
) t
ORDER BY ValOrder
I have a prob in following Select query.
select *
from ".$table2." a,purpose_details b
where b.purpose_code=a.purpose and purpose_code in(1,4,6,7,10)
and ((fromdt<='$frmdate'and todt>='$frmdate')
or (fromdt<='$frmdate' and todt='1111-11-11'))
and substr(a.appno,4,1)!=6
order by purpose_priority,
cast(substr(a.case_no,12,4) as int) ,cast(substr(a.case_no,4,1) as int),
cast(substr(a.case_no,5,7) as int),cast(substr(a.appno,12,4) as int) ,
cast(substr(a.appno,4,1) as int),cast(substr(a.appno,5,7) as int)";
the problem is the rows in the table2 may or may not have value of appno. (ie) appno value may be NULL for some of rows.
Due to appno is one among in the order by column this particular code retuns invalid input error.
Finally What i want is the select query arrange the columns by appno only when the appno value is not null.
Note: The order by clause for the rest of the columns should be applied on both situations.
Pls help me to sort it out. Thanks in Advance.
Order by can definitly handle null values but substr cannot.
You should replace your
Substr (col, ...
With
Case when col is null then null else substr (col, ...
This is not really a problem because I solved it. But, I wanted to share something that ate my brain today. So, run this query and check it out:
The query:
select 2 as ID1,0 as ID2 into #TEMP
insert into #TEMP (ID1,ID2)
values (2,1),(2,2),(2,0)
select
case when min(case when ID1=2 and ID2=0 then 0
else 1
end)=0 then 0
else sum(log(ID2))
end
from #TEMP
The fix:
select
case when min(case when ID1=2 and ID2=0 then 0
else 1
end)=0 then 0
else sum(log(case when ID1=2 and ID2<>0 then ID2
else 1
end))
end
from #TEMP
My query was larger and more difficult to debug, but what do you say about the plan that MSSQL is making and the fact that it gets it wrong with this query? How can it be modified to work except my little fix that I showed before? I am guessing that computing scalars before the query would make things slow if the scalars are not easy to compute and we compute for all values.
SQL Server does not perform short circuit evaluation (i.e. should not be relied upon). It's a fairly well known problem.
Ref:
Don’t depend on expression short circuiting in T-SQL (not even with CASE)
Short Circuit
Short-Circuit Evaluation
Is the SQL WHERE clause short-circuit evaluated?
EDIT: I misunderstood the question with my original answer.
I supposed you could add a where clause, as shown below. Side note: this query might benefit from an index on (ID1, ID2).
select
sum(log(convert(float, ID2)))
from #TEMP
where
-- exclude all records with ID1 = 2 if there are any records with ID1 = 2 and ID2 = 0
not exists (
select 1
from #TEMP NoZeros
where
NoZeros.ID1 = #TEMP.ID1
and NoZeros.ID2 = 0
)
Update: Just in case performance is a concern, I got fairly comparable performance from this query after adding the following indexes:
create index ix_TEMP_ID1_ID2 on #TEMP (ID1, ID2)
create index ix_TEMP_ID2 on #TEMP (ID2) include (ID1)
Original Answer
How about modifying your sum function as shown below?
sum(case ID2 when 0 then null else log(convert(float, ID2)) end)
Here's the scenario:
I have a table with 3 columns: 'KeyColumn', 'SubKeyColumn' and 'BooleanColumn', where the first two are the primary keys of the table.
For my query, I'd like to count the number of rows there are for any given value in 'KeyColumn', and I'd also like to know which ones have a value of true for 'BooleanColumn'. My initial thought was to create a query like this:
SELECT
COUNT(*)
,COUNT(CASE WHEN BooleanColumn = 1 THEN 1 ELSE 0 END)
FROM
MyTable
GROUP BY
KeyColumn
However, the 2nd part does not work (I'm not entirely sure why I thought it would to begin with). Is it possible to do something like this in one query? Or am I going to need to do multiple queries to make this happen?
Change COUNT to SUM in the 2nd part. ;)
... CASE WHEN BooleanColumn = 1 THEN 1 ELSE NULL END ...
COUNT counts the NON-NULL rows.
You could also do SUM(CAST(BooleanColumn AS TINYINT))