SQL Specific Order - sql

Given the following query:
SELECT DISTINCT n.iswinner, i.name
FROM nominees n, institutions i
WHERE n.iid = i.iid and n.filmname = '127 Hours'
ORDER BY name
I get the output:
iswinner name
NULL academy awards
NULL baftas
NULL critics' choice awards
NULL golden globes
NULL screen actors guild
NULL writers guild of america
I am trying to figure out if it is possible to order this output in a more specific manner. The order I am looking for is to list first 'academy awards', then 'golden globes' then anything with a 'guild' in its name, and finally anything else alphabetically. So therefore the output I'm looking for is more along the lines of this:
iswinner name
NULL academy awards
NULL golden globes
NULL screen actors guild
NULL writers guild of america
NULL bafta
NULL critics' choice awards
Is there a way to do such a thing? I believe I should use something like CASE, but I couldn't seem to figure out the correct syntax for it. Thanks for any help.

Yes there is a way to do something like this and just like you thought, you can do this with a CASE statement. Something like the following should do the trick:
SELECT
DISTINCT n.iswinner,
i.name,
CASE
WHEN i.name = 'academy awards' THEN 1
WHEN i.name = 'golden globes' THEN 2
WHEN i.name like '%guild%' THEN 3
ELSE 4
END AS Order
FROM nominees n, institutions i
WHERE n.iid = i.iid and n.filmname = '127 Hours'
ORDER BY
Order,
i.name
So, to give you a little more information on what is being done here. In the ORDER clause, we're ordering by a CASE statement. Basically, based upon what the i.name field is, we are assigning an integer number to order by. academy awards is assigned 1, golden globes is assigned 2, anything that contains 'guild' is assigned 3, and anything else is assigned 4. So we first order by this CASE statement (which gives the specific ordering you want) and then order by the name field which will satisfy your the second requirement of ordering anything else by name (which we previously assigned the value of 4 in the CASE statement for ordering).
I hope this makes sense to you.
Same query using GROUP BY rather than DISTINCT:
SELECT
n.iswinner,
i.name
FROM nominees n, institutions i
WHERE n.iid = i.iid and n.filmname = '127 Hours'
GROUP BY
n.iswinner,
i.isname
ORDER BY
CASE
WHEN i.name = 'academy awards' THEN 1
WHEN i.name = 'golden globes' THEN 2
WHEN i.name like '%guild%' THEN 3
ELSE 4
END,
i.name

order by
case
when name = 'academy awards' then 1
when name = 'golden globes' then 2
when name like '%guild%' then 3
else 4
end
, name

No need for a case clause. SQL Fiddle
select *
from (
select distinct n.iswinner, i.name
from nominees n, institutions i
where n.iid = i.iid and n.filmname = '127 Hours'
) s
order by
name != 'academy awards',
name != 'golden globes',
name not like '%guild%',
name
false orders before true

Related

SQL query syntax in CASE WHEN ELSE END to count

Writing a query to find the number of ED visits that were discharged from non-ED units.
The column dep.ADT_UNIT_TYPE_C column stores 1 if the unit was an ED unit.
Assume NULL values are non-ED units for the purpose of this query.
Which of the following produces this number?
I am thinking it is A because in my mind, that sound the correct syntax.
COUNT(CASE WHEN THEN ELSE END standard format)
A has that.
B doesn't have the THEN? so it is incorrect syntax?
Please help me understanding the nuances between these choices.
A.)
COUNT( CASE WHEN dep.ADT_UNIT_TYPE_C is NULL OR dep.ADT_UNIT_TYPE_C <> 1 THEN NULL
ELSE 1
END )
B.)
COUNT( CASE WHEN dep.ADT_UNIT_TYPE_C is NULL or dep.ADT_UNIT_TYPE_C <> 1
ELSE NULL
END)
C.)
CASE WHEN dep.ADT_UNIT_TYPE_C Is NULL or dep.ADT_UNIT_TYPE_C <> 1 THEN COUNT (NULL)
ELSE COUNT (1)
END
D.)
CASE WHEN dep.ADT_UNIT_TYPE_C is NULL or dep.ADT_UNIT_TYPE_C <> 1 THEN COUNT(1)
ELSE COUNT(NULL)
END
You can count the records that are returned COUNT(*) and put the condition in the where clause.
If you are using Oracle, you can use NVL.
The sample below is for Oracle, but if using mysql or SQL server, you can use the ISNULL Function.
SELECT COUNT(*) FROM dep WHERE NVL(ADT_UNIT_TYPE_C, 0) != 1
It looks like however, you are joining this to another table, probably a visit table. So, you want to count visits. Visits probably stores some kind of department id or way to join it to departments.
Something like this:
SELECT COUNT(*) FROM visit v, departments d WHERE v.dep_id = d.dep_id AND NVL(d.ADT_UNIT_TYPE_C, 0) !=1
If you want the entire list like shown above, you want to use a group by. This will show you the count for each visit by department type.
SELECT COUNT(*) FROM visit v, departments d GROUP BY d.ADT_UNIT_TYPE_C

How to retrieve list from SQL alphabetically except one item?

I have a table with a column for Occupations in a table in SQL. Along with a few occupations, I also have an item for 'others'. I will display these in a dropdownlist and on selecting 'others' I will show a text box.
Ex: Business
Student
Employee
Others
I want to retrieve the list in Ascending Order, but when I do that using ORDER BY ASC 'Others' will come somewhere in between. I want it to be at the end of the list being returned.
Like Business
Employee
Student
Other
Please suggest a solution to keep the Others at the end of list while retrieving.
(Note: The list is dynamic and will be changing , so I cannot hardcode)
Try something like
SELECT * FROM
(
SELECT *,
CASE WHEN <YourValue> = 'Others' THEN 1 ELSE 0 END AS PrimaryOrder
FROM <YourTable>
) AS SubQuery01
ORDER BY PrimaryOrder, YourOrderByCriteria
A possible solution:
select occupations from mytable where occupations != 'Others' order by 1 ASC
union
select occupations from mytable where occupations == 'Others';
but it's overkill, you can add others by hand
I have tried out a solution and is working for me..
SELECT O.NAME FROM OCCUPATIONTABLE O
ORDER BY CASE
WHEN O.NAME = 'Others'
THEN 1
ELSE 0
END ASC
,O.NAME ASC

Select an ID if count is equal to 1

I am trying to write a query which needs to find an ID number from 3 WHERE values based on the result only being equal to 1.
So say i want to find a patient's ID and my where clause matches the firstname, lastname and DOB. If there are 2 results because of duplicates, i need the output to be NIL else it should return the patient ID.
if(select count(*)
from patient
where last_name = 'JAMES'
and first_name = 'JONES'
and birth_DtTM = '1980-01-01') > 1
print 'NULL' else return Pat_ID1
This is kind of what i am leading towards.
Thanks guys
select case when count(*)> 1
then 'NULL' else Pat_ID1 end
from patient
where last_name = 'JAMES'
and first_name = 'JONES'
and birth_DtTM = '1980-01-01'
group by Pat_ID1
try below.
;WITH CTE(Pat_ID1,last_name,first_name,birth_DtTM,dup_rows)
as
(
SELECT Pat_ID1,last_name,first_name,birth_DtTM,ROW_NUMBER() OVER(PARTITION BY last_name,first_name,birth_DtTM ORDER BY Pat_ID1) AS dup_rows FROM patient
)
SELECT
case when dup_rows>1 then null
when dup_rows=1 then Pat_ID1
end
FROM CTE
You can do it like this:
SELECT
PatientID = CASE COUNT(*) WHEN 1 THEN MAX(Pat_ID1) END
FROM
patient
WHERE
last_name = 'JAMES'
AND first_name = 'JONES'
AND birth_DtTM = '1980-01-01'
;
The CASE expression will evaluate either to the single Pat_ID1 matching the request or to NULL (if COUNT(*) is anything but 1).
As you can see, the Pat_ID1 value is obtained with the help of an aggregate function (by the way, you can use MIN instead of MAX just as well). This is because the presence of COUNT(*) in the query automatically implies grouping and now, if you want to reference columns of the underlying row set, you must only access their aggregated values.

SQL Nested Select statements with COUNT()

I'll try to describe as best I can, but it's hard for me to wrap my whole head around this problem let alone describe it....
I am trying to select multiple results in one query to display the current status of a database. I have the first column as one type of record, and the second column as a sub-category of the first column. The subcategory is then linked to more records underneath that, distinguished by status, forming several more columns. I need to display every main-category/subcategory combination, and then the count of how many of each sub-status there are beneath that subcategory in the subsequent columns. I've got it so that I can display the unique combinations, but I'm not sure how to nest the select statements so that I can select the count of a completely different table from the main query. My problem lies in that to display the main category and sub category, I can pull from one table, but I need to count from a different table. Any ideas on the matter would be greatly appreciated
Here's what I have. The count statements would be replaced with the count of each status:
SELECT wave_num "WAVE NUMBER",
int_tasktype "INT / TaskType",
COUNT (1) total,
COUNT (1) "LOCKED/DISABLED",
COUNT (1) released,
COUNT (1) "PARTIALLY ASSEMBLED",
COUNT (1) assembled
FROM (SELECT DISTINCT
(t.invn_need_type || ' / ' || s.code_desc) int_tasktype,
t.task_genrtn_ref_nbr wave_num
FROM sys_code s, task_hdr t
WHERE t.task_genrtn_ref_nbr IN
(SELECT ship_wave_nbr
FROM ship_wave_parm
WHERE TRUNC (create_date_time) LIKE SYSDATE - 7)
AND s.code_type = '590'
AND s.rec_type = 'S'
AND s.code_id = t.task_type),
ship_wave_parm swp
GROUP BY wave_num, int_tasktype
ORDER BY wave_num
Image here: http://i.imgur.com/JX334.png
Guessing a bit,both regarding your problem and Oracle (which I've - unfortunately - never used), hopefully it will give you some ideas. Sorry for completely messing up the way you write SQL, SELECT ... FROM (SELECT ... WHERE ... IN (SELECT ...)) simply confuses me, so I have to restructure:
with tmp(int_tasktype, wave_num) as
(select distinct (t.invn_need_type || ' / ' || s.code_desc), t.task_genrtn_ref_nbr
from sys_code s
join task_hdr t
on s.code_id = t.task_type
where s.code_type = '590'
and s.rec_type = 'S'
and exists(select 1 from ship_wave_parm p
where t.task_genrtn_ref_nbr = p.ship_wave_nbr
and trunc(p.create_date_time) = sysdate - 7))
select t.wave_num "WAVE NUMBER", t.int_tasktype "INT / TaskType",
count(*) TOTAL,
sum(case when sst.sub_status = 'LOCKED' then 1 end) "LOCKED/DISABLED",
sum(case when sst.sub_status = 'RELEASED' then 1 end) RELEASED,
sum(case when sst.sub_status = 'PARTIAL' then 1 end) "PARTIALLY ASSEMBLED",
sum(case when sst.sub_status = 'ASSEMBLED' then 1 end) ASSEMBLED
from tmp t
join sub_status_table sst
on t.wave_num = sst.wave_num
group by t.wave_num, t.int_tasktype
order by t.wave_num
As you notice, I don't know anything about the table with the substatuses.
You can use inner join, grouping and count to get your result:
suppose tables are as follow :
cat (1)--->(n) subcat (1)----->(n) subcat_detail.
so the query would be :
select cat.title cat_title ,subcat.title subcat_title ,count(*) as cnt from
cat inner join sub_cat on cat.id=subcat.cat_id
inner join subcat_detail on subcat.ID=am.subcat_detail_id
group by cat.title,subcat.title
Generally when you need different counts, you need to use the CASE statment.
select count(*) as total
, case when field1 = "test' then 1 else 0 end as testcount
, case when field2 = 'yes' then 1 else 0 endas field2count
FROM table1

giving priority to values in an SQL stmt

is there any way i can do a query to specify that I want to give priority to some value?
for instance i have:
SELECT TOP (20)
r.MD5, r.Title, r.Link, t.Category, t.tfidf, COUNT(r.MD5) AS matching_terms
FROM
Resource AS r INNER JOIN tags AS t ON r.MD5 = t.MD5
WHERE
(t.Category IN ('algorithm', 'k-means', 'statistics', 'clustering', 'science'))
GROUP BY r.MD5, r.Title, r.Link, t.Category, t.tfidf
ORDER BY matching_terms DESC, t.tfidf DESC
i want that 'algorithm' is given higher priority when finding results. any ideas?
I'm not sure how high a priority you want to make 'algorithm', but in any case, you can add this to the ORDER BY clause, in order to make it the most important category (all other categories are equally important):
ORDER BY ..., CASE t.Category = 'algorithm' THEN 0 ELSE 1 END, ...
If however your concept of "priority" is somehow correlated with the importance of the matching_terms expression, you could also try something like this (you'd have to nest your above select)
SELECT TOP(20) FROM (
[your original select without TOP(20) clause]
)
ORDER BY (matching_terms * CASE t.Category = 'algorithm'
THEN 1.5 ELSE 1 END) DESC, t.tfidf DESC
But that's just an example to give you an idea.
UPDATE: Following you comment, you can generate a case statement like this:
ORDER BY CASE t.Category WHEN 'algorithm' THEN 0
WHEN 'k-means' THEN 1
WHEN 'statistics' THEN 2
WHEN 'clustering' THEN 3
WHEN 'science' THEN 4 END
Or alternatively (especially if your list of categories is large), then you should add a sort field to tags, containing the priority. Then you could simply order by sort
SELECT TOP (10) r.MD5, r.Title, r.Link, t.Category, t.tfidf, COUNT(r.MD5) AS matching_terms
FROM Resource AS r INNER JOIN
tags AS t ON r.MD5 = t.MD5
WHERE (t.Category IN ('astrophysics', 'athletics', 'sports', 'football', 'soccer'))
GROUP BY r.MD5, r.Title, r.Link, t.Category, t.tfidf
ORDER BY (CASE t .Category WHEN 'astrophysics' THEN 0 WHEN 'athletics' THEN 1 WHEN 'sports' THEN 2 WHEN 'football' THEN 3 WHEN 'soccer' THEN 4 END)
Thanks for giving me the idea Lukas Eder