SQL Specific Item on top - sql

I am having this query for a photo contest:
SELECT * FROM `users` ORDER BY entry_id DESC
The result gives 10 records with entry_id 10, 9, 8, 7, ......1
What can I do to pick a specific entry on the top?
As there is a requirement if there is a refer ID, entry show first.
So the expected result should be: 4,10,9,8,7,6,5,3,2,1 if 4 if a refer ID.

Try this:
SELECT *
FROM `users`
ORDER BY (CASE WHEN entry_id = 4 THEN 0 ELSE 1 END), entry_id DESC;

for more Dynamic Approach create table value Function
create function OrderData(#a int)
returns #t table ( id int)
as
begin
insert into #t
SELECT *
FROM ab
ORDER BY (CASE WHEN id = #a THEN 0 ELSE 1 END), id DESC
return;
end;
select * from dbo.abc(4)
output
4,10,9,8,7,6,5,3,2,1
select * from dbo.abc(5)
output
5,10,9,8,7,6,4,3,2,1

Related

Selecting distinct values

Trying to get a selection of records where if COUNT ([WHO]) > 1 then select [WHO] where the [LIT] <> 0.
Example if [WHO] = '12082132' , '12082132' and [LIT] = 0, then ignore [WHO].
WHO LIT COUNT
3517015 7 1
3523687 0 1
12057744 0 2
12058316 7 1
12059820 7 1
12082132 2 2
12082132 5 1
12082132 1 3
12082132 14 1
12082132 0 1
I have tried grouping, case statements, but I think I am trying to get something that is not possible. Any help will do.
Expected results
WHO LIT COUNT
3517015 7 1
12058316 7 1
12059820 7 1
Trying to get a selection of records where if COUNT ([WHO]) > 1 then select [WHO] where the [LIT] <> 0.
Is this what you want?
select t.*
from (select t.*, count(*) over (partition by who) as cnt
from t
) t
where cnt > 1 and lit <> 0;
You can use not exists & use window function :
select t.*, count(*) over (partition by t.who) as cnt
from table t
where not exists (select 1
from table t1
where t1.who = t.who and t1.lit = 0
);
Simple NOT IN will work
SELECT * FROM #Table
WHERE [WHO] NOT IN (
SELECT DISTINCT [WHO]
FROM #Table
WHERE CASE WHEN [LIT] >= 1 THEN 0 ELSE 1 END = 1
)
This is an example, I hope it helps you,I think that it does what you want but its a little tricky, maybe can lead you to an answers at least if it's not
what you want.
drop table #testMr
drop table #checkTest
create table #testMr(who numeric, lit numeric, count_x numeric)
create table #checkTest(who numeric, lit numeric, count_x numeric,countWho numeric)
insert into #testMr values(3517015,7,1)
insert into #testMr values(3523687,0,1)
insert into #testMr values(12057744,0,1)
insert into #testMr values(12058316,7,1)
insert into #testMr values(12082132,1,3)
insert into #testMr values(12082132,14,1)
insert into #testMr values(12082132,7,1)
insert into #testMr values(12082132,0,1)
insert into #checkTest
select who,sum(lit) as [lit],sum(count_x) as [CountX],count(who) as [CountWho] from #testMr
where who in(select b.who from #testMr as b where b.lit<>0) group by who having count(who)>1
if(select count(*) from #checkTest)>0
begin
--there are some invalid values so we filter by the lit<>0 and remove the invalid ones.
select * from #testMr where lit<>0 and who not in(select b.who from #checkTest as b)
end
else
begin
--'All values are Ok and we filter by the count who.'
select who,sum(lit) as [lit],sum(count_x) as [CountX] from #testMr group by who having count(who)>1
end

SQL Server - Get column who have specific value

I have a SQL query which returns :
id | value
1 a
1 a
1 b
2 a
2 a
I want to get only id who have only the value a. So the id 2
How to do this ?
You can use aggregation and having clause to check if all the rows have value 'a' for a given id:
Using Count:
select id
from t
group by id
having count(*) = count(case when value = 'a' then 1 end);
Or using Sum
select id
from t
group by id
having SUM(case when value = 'a' then 0 else 1 end) = 0;
Use the next code:-
Select id
from #test
group by id
having sum (case when value = 'a' then 0 else 1 end) = 0
The clue is passing 0 for 'a' and pass 1 for other, then having sum equals 0
This is slightly slower than #Gurwinder Singh's answer but can be more readable if performance is not your top priority.
CREATE TABLE tmp (id int, [value] char(1))
INSERT INTO tmp values (1,'a'),(1,'a'),(1,'b'),(2,'a'),(2,'a')
SELECT DISTINCT id
FROM tmp a
WHERE [value] = 'a'
AND id NOT IN (
SELECT id FROM tmp
WHERE [value] <> 'a')

Select statement to return constant when no records found in table in SQL Server 2008

I am have a table with data and now i need to return zero in select statement if there is no records in table for example. I need to use it in Stored Procedure.
-- If no records exists in below select statement
SELECT ID,Text,Date FROM tblData WHERE ID = 12
IF (##ROWCOUNT = 0)
BEGIN
SELECT -5 AS ID
END
Output:
ID Text Date
ID
-5
Expected output
ID
-5
If you want to return 1 row even when there is no match, you can use aggregation:
SELECT (CASE WHEN COUNT(*) = 0 THEN -5 ELSE MAX(ID) END) as ID
FROM tblData
WHERE ID = 12;
I always use an Exists statment.
if exists(SELECT ID FROM tblData WHERE ID = 12)
select 0 as RowsExist
else
select 1 as RowsExist
For a single scalar value you could use something like;
SELECT ISNULL((SELECT ID FROM tblData WHERE ID = 12), 0) as ID
Rhys
SELECT (CASE WHEN Ta.ID IS NULL THEN TBL.ID
ELSE Ta.ID END) AS ID,Ta.Text,Ta.Date
FROM (VALUES(-5)) AS TBL(ID)
LEFT JOIN
(
SELECT ID,Text,Date FROM tblData WHERE ID = 12
)
AS Ta ON Ta.ID = Ta.ID

SQL - Combining incomplete

I'm using Oracle 10g. I have a table with a number of fields of varying types. The fields contain observations that have been made by made about a particular thing on a particular date by a particular site.
So:
ItemID, Date, Observation1, Observation2, Observation3...
There are about 40 Observations in each record. The table structure cannot be changed at this point in time.
Unfortunately not all the Observations have been populated (either accidentally or because the site is incapable of making that recording). I need to combine all the records about a particular item into a single record in a query, making it as complete as possible.
A simple way to do this would be something like
SELECT
ItemID,
MAX(Date),
MAX(Observation1),
MAX(Observation2)
etc.
FROM
Table
GROUP BY
ItemID
But ideally I would like it to pick the most recent observation available, not the max/min value. I could do this by writing sub queries in the form
SELECT
ItemID,
ObservationX,
ROW_NUMBER() OVER (PARTITION BY ItemID ORDER BY Date DESC) ROWNUMBER
FROM
Table
WHERE
ObservationX IS NOT NULL
And joining all the ROWNUMBER 1s together for an ItemID but because of the number of fields this would require 40 subqueries.
My question is whether there's a more concise way of doing this that I'm missing.
Create the table and the sample date
SQL> create table observation(
2 item_id number,
3 dt date,
4 val1 number,
5 val2 number );
Table created.
SQL> insert into observation values( 1, date '2011-12-01', 1, null );
1 row created.
SQL> insert into observation values( 1, date '2011-12-02', null, 2 );
1 row created.
SQL> insert into observation values( 1, date '2011-12-03', 3, null );
1 row created.
SQL> insert into observation values( 2, date '2011-12-01', 4, null );
1 row created.
SQL> insert into observation values( 2, date '2011-12-02', 5, 6 );
1 row created.
And then use the KEEP clause on the MAX aggregate function with an ORDER BY that puts the rows with NULL observations at the end. whatever date you use in the ORDER BY needs to be earlier than the earliest real observation in the table.
SQL> ed
Wrote file afiedt.buf
1 select item_id,
2 max(val1) keep( dense_rank last
3 order by (case when val1 is not null
4 then dt
5 else date '1900-01-01'
6 end) ) val1,
7 max(val2) keep( dense_rank last
8 order by (case when val2 is not null
9 then dt
10 else date '1900-01-01'
11 end) ) val2
12 from observation
13* group by item_id
SQL> /
ITEM_ID VAL1 VAL2
---------- ---------- ----------
1 3 2
2 5 6
I suspect that there is a more elegant solution to ignore the NULL values than adding the CASE statement to the ORDER BY but the CASE gets the job done.
i dont know about commands in oracle but in sql you could use some how that
first use pivot table is contains consecutives numbers 0,1,2...
i'm not sure but in oracle the function "isnull" is "NVL"
select items.ItemId,
case p.i = 0 then observation1 else '' end as observation1,
case p.i = 0 then observation1 else '' end as observation2,
case p.i = 0 then observation1 else '' end as observation3,
...
case p.i = 39 then observation4 else '' as observation40
from (
select items.ItemId
from table as items
where items.item = _paramerter_for_retrive_only_one_item /* select one item o more item where you filter items here*/
group by items.ItemId) itemgroup
left join
(
select
items.ItemId,
p.i,
isnull( max ( case p.i = 0 then observation1 else '' end ), '' ) as observation1,
isnull( max ( case p.i = 1 then observation2 else '' end ), '' ) as observation2,
isnull( max ( case p.i = 2 then observation3 else '' end), '' ) as observation3,
...
isnull( max ( case p.i = 39 then observation4), '' ) as observation40,
from
(select i from pivot where id < 40 /*you number of columns of observations, that attach one index*/
)
as p
cross join table as items
lef join table as itemcombinations
on item.itemid = itemcombinations.itemid
where items.item = _paramerter_for_retrive_only_one_item /* select one item o more item where you filter items here*/
and (p.i = 0 and not itemcombinations.observation1 is null) /* column 1 */
and (p.i = 1 and not itemcombinations.observation2 is null) /* column 2 */
and (p.i = 2 and not itemcombinations.observation3 is null) /* column 3 */
....
and (p.i = 39 and not itemcombinations.observation3 is null) /* column 39 */
group by p.i, items.ItemId
) as itemsimplified
on itemsimplified.ItemId = itemgroup.itemId
group by itemgroup.itemId
About pivot table
create an pivot table, Take a look at that
pivot table schema
name: pivot columns: {i : datatype int}
How populate
create foo table
schema foo
name: foo column: value datatype varchar
insert into foo
values('0'),
values('1'),
values('2'),
values('3'),
values('4'),
values('5'),
values('6'),
values('7'),
values('8'),
values('9');
/* insert 100 values */
insert into pivot
select concat(a.value, a.value) /* mysql */
a.value + a.value /* sql server */
a.value | a.value /* Oracle im not sure about that sintax */
from foo a, foo b
/* insert 1000 values */
insert into pivot
select concat(a.value, b.value, c.value) /* mysql */
a.value + b.value + c.value /* sql server */
a.value | b.value | c.value /* Oracle im not sure about that sintax */
from foo a, foo b, foo c
the idea about pivot table can consult in "Transact-SQL Cookbook By Jonathan Gennick, Ales Spetic"
I have to admit that the above solution (by Justin Cave) is simpler and easier to understand but this is another good option
at the end like you said you solved

SQL retrieval from tables

I have a table something like
EMPLOYEE_ID DTL_ID COLUMN_A COLUMN_B
---------------------------
JOHN 0 1 1
JOHN 1 3 1
LINN 0 1 12
SMITH 0 9 1
SMITH 1 11 12
It means for each person there will be one or more records with different DTL_ID's value (0, 1, 2 .. etc).
Now I'd like to create a T-SQL statement to retrieve the records with EMPLOYEE_ID and DTL_ID.
If the specified DTL_ID is NOT found, the record with DTL_ID=0 will be returned.
I know that I can achieve this in various ways such as checking if a row exists via EXISTS or COUNT(*) first and then retrieve the row.
However, I'd like to know other possible ways because this retrieval statement is very common in my application and my table have hundred thousand of rows.
In the above approach, I've had to retrieve twice even if the record with the DTL_ID specified exists, and I want to avoid this.
Like this:
SELECT *
FROM table
WHERE EMPLOYEE_ID = ?? AND DTL_ID = ??
UNION
SELECT *
FROM table
WHERE EMPLOYEE_ID = ?? AND DTL_ID = 0
AND NOT EXISTS (SELECT *
FROM table
WHERE EMPLOYEE_ID = ?? AND DTL_ID = ??)
You will of course have to fill in the ?? with the proper number.
If DTL_ID is always 0 or positive:
SELECT TOP 1 * FROM table
where EmployeeID = #EmployeeID and DTL_ID in (#DTL_ID,0)
order by DTL_ID desc
If you're working across multiple employees in a single query, etc, then you might want to use ROW_NUMBER() if your version of SQL supports it.
Use ISNULL(DTL_ID, 0) in your final SELECT query
SELECT E1.EMPLOYEE_ID, ISNULL(E2.DTL_ID, 0), E1.COLUMN_A, E1.COLUMN_B EMPLIYEES AS E1
LEFT JOIN EMPLIYEES AS E2
ON E1.EMPLOYEE_ID = E2.EMPLOYEE_ID AND E2.DTL_ID = 42
You can use top and union, e.g.:
declare #t table(id int, value int, c char)
insert #t values (1,0,'a'), (1,1,'b'), (1,2,'c')
declare #id int = 1;
declare #value int = 2;
select top(1) *
from
(
select *
from #t t
where t.value = #value and t.id = #id
union all
select *
from #t t
where t.value = 0
)a
order by a.value desc
If #value = 2 than query returns 1 2 c. If #value = 3 than query returns 1 0 a.
SELECT MAX(DTL_ID) ...
WHERE DTL_ID IN (#DTL_ID, 0)