SQL Order By list of strings? - sql

I wish to do a select on a table and order the results by a certain keyword or list of keywords. For example I have a table like so:
ID Code
1 Health
2 Freeze
3 Phone
4 Phone
5 Health
6 Hot
so rather than just do a simple Order By asc/desc I'd like to order by Health, Phone, Freeze, Hot. Is this possible?

Try using this:
select * from table
order by FIELD(Code, 'Health', 'Phone', 'Freeze', 'Hot')

Here's a horrible hack:
select * from table
order by (
case Code
when 'Health' then 0
when 'Phone' then 1
when 'Freeze' then 2
when 'Hot' then 3
end
)

You can join with the Keywords table, and include a sequence column, and ORDER BY Keyword.Sequence.
Example your keywords table looks like this:
ID Code Sequence
1 Health 1
2 Freeze 3
3 Phone 2
4 Hot 4
Then you can join.
SELECT *
FROM MyTable INNER JOIN
Keywords ON Keywords.ID = MyTable.KeywordID
ORDER BY Keywords.Sequence
Hope this gives you the idea.

Nowadays MySQL has a function called find_in_set()
Use it like this:
select * from table
order by find_in_set(Code,'Health','Phone','Freeze','Hot')

Is this just a one off ORDER BY or something that you're going to want to do often and on more values than specified here?
The order that you have given is arbitrary, therefore an identifier needs to be given to achieve what you want
SELECT
ID,
Code,
CASE Code
WHEN 'Health' THEN 1
WHEN 'Phone' THEN 2
WHEN 'Freeze' THEN 3
WHEN 'Hot' THEN 4
END As OrderBy
FROM Table
ORDER BY
OrderBy
Or
SELECT
ID,
Code
FROM Table
ORDER BY
CASE Code
WHEN 'Health' THEN 1
WHEN 'Phone' THEN 2
WHEN 'Freeze' THEN 3
WHEN 'Hot' THEN 4
END
(I'm not familiar with MySQL but the above would work in SQL Server. The syntax for MySQL won't be too different)
If you're likely to want to do this often, then create an OrderBy column on the table or create an OrderBy table with a FK link to this table and specify an OrderBy numerical field in that.

Hi this is a SQL Server query but I am sure you can do this in MySQL as well:
SELECT ID, Code
FROM x
ORDER BY
CASE Code WHEN 'Health' THEN 1
WHEN 'Phone' THEN 2
WHEN 'Freeze' THEN 4
WHEN 'Hot' THEN 5
ELSE 6 END ASC
, Code ASC

Couple options:
Add OrderCode column with numerical
desired order
Add a table with FK to this table ID
and OrderCode

Yes join your results to your code table and then order by code.CodeOrder
EDIT: Explaing the use of the code table...
Create a separate table of Codes (CodeId, Code, CodeOrder) and join to this and order by CodeOrder. This is nicer than doing the order by (case...) hack suggested since you can easily change the codes and the orders.

Related

How do I generate a table of IDs which have only one attribute each?

I have a table that looks like this
id attribute
1 a
1 a
2 b
2 a
And I want to collect all of the IDs which have ONLY attribute a. So in the example case:
id
1
My initial thought was to use a where, but that would return:
id
1
1
2
Because 2 also has an "a" attribute in one instance.
P.S. I realize the phrasing of the title is ambiguous; maybe there's a better term than attribute to use in this case?
ohh I just saw hive but this is pretty standard sql give it a try.
SELECT
ID
FROM
TABLENAME
GROUP BY
ID
HAVING
COUNT(DISTINCT attribute) = 1
Having is like a where statement after the GROUP BY aggregation has occurred.
HiveQL equivalent of SQL using group by ,having and distinct
select id from (select id,count(distinct attribute) cnt from table_actual group by id having cnt='1') tableouter;

Sql to get unique rows

I have a table as below.
OId CustId CustSeq
1 A 10
1 A 20
2 A 10
2 A 20
I'm trying to extract unique records as below.
OId CustId CustSeq (Different OIds with different CustSeqs)
1 A 10
2 A 20
May I know how I could come out the query to extract like above?
Just use DISTINCT. That's what it was desgined for although group by will work.
http://www.techonthenet.com/oracle/distinct.php
SELECT DISTINCT OID, CUSTID, CUSTSEQ
FROM TABLE_NAME
Use DISTINCT, and also use Group By for the 2 columns CustId & CustSeq
Check here for example Is it possible to GROUP BY multiple columns using MySQL?

Updating tables from generate_series(int, int) function Postgres 9.0

I have a table with data in it I want to keep, but I have to add a new column of integers for ordering purposes. Now this ordering will be different depending on the clientID as each different client wants different ordering. So in my example there are 3 different clients, the first client has 10 rows of data the second has 15, and the third has 87. So basically I'm looking for a query that will let me update the ordering column in a way that will allow me to do a select on the table that would give results like this.
Select ordering from table Where clientID = 1
-----------
Ordering
1
2
3
4
5
6
7
8
9
10
Now the query I'm currently using to do this is
UPDATE data SET ordering = generate_series
FROM (SELECT * FROM generate_series(1,87)) as k <
where clientid = '3'
This will update all the correct rows but only with the first value, so all the values in ordering would be 1. I feel like I'm missing something here or this just doesn't work in postgres as it does in other SQL languages. Any solution here will help I would also like to know why my update would not work as I expected in postgres. Also I cannot change versions of postgres based on the environment I work in.
I don't see why you would need generate_series(). A window function that numbers all rows for each client should do:
update data
set ordering = t.rn
from (select pk_column,
row_number() over (partition by clientid order by pk_column) as rn
from data
) t
where t.pk_column = data.pk_column;
pk_column is the primary key column of the table data

How to index two columns automatically in sql

I have a table in sql having two fields 'JOB_NUMBER' 'SRno', the relation between the two is such that each job number has many SRNO starting from 1,2,3 and so on,every new Job number has to have a SR no starting form 1,
so my ideal table should some what look like this:
JOB_NUMBER SRno
1 1
1 2
1 3
2 1
2 2
3 1 and so on.......
What I want to do is to achive this indexing in sql itself ,can I do this ,is so how?
If there is another column on the table that is something like a timestamp (e.g. time submitted), then you can do something like:
select job_number,
row_number() over (partition by job_number order by time_submitted asc) as SRno
from tbl
You could make that into a view and you're good to go. Keep in mind that this will be sensitive to data modifications (i.e. if someone inserts a row between two other rows, the rows after the inserted one will be "renumbered"). Also keep in mind that this won't store the SRno on the table; it has to be calculated dynamically.
You mean auto-numbering (indexing is something different in DBMS's). It can be achieved using a trigger. But that's DBMS-specific issue. Check if your database supports triggers.
Are you looking for something like this..
select JOB_NUMBER,ROW_NUMBER() over(partition by JOB_NUMBER order by JOB_NUMBER)
as SRno from table_jobs

SQL Precedence Query

I have a logging table which has three columns. One column is a unique identifier, One Column is called "Name" and the other is "Status".
Values in the Name column can repeat so that you might see Name "Joe" in multiple rows. Name "Joe" might have a row with a status "open", another row with a status "closed", another with "waiting" and maybe one for "hold". I would like to, using a defined precedence in this highest to lowest order:("Closed","Hold","Waiting" and "Open") pull the highest ranking row for each Name and ignore the others. Anyone know a simple way to do this?
BTW, not every Name will have all status representations, so "Joe" might only have a row for "waiting" and "hold", or maybe just "waiting".
I would create a second table named something like "Status_Precedence", with rows like:
Status | Order
---------------
Closed | 1
Hold | 2
Waiting | 3
Open | 4
In your query of the other table, do a join to this table (on Status_Precedence.Status) and then you can ORDER BY Status_Precedence.Order.
If you don't want to create another table, you can assign numeric precedence using a SELECT CASE
Select Name, Status, Case Status
When 'Closed' then 1
When 'Hold' then 2
When 'Waiting' then 3
When 'Open' Then 4
END
as StatusID
From Logging
Order By StatusId -- Order based on Case
A lookup table is also a good solution though.
I ended up using matt b's solution and using this final query to filter out the lower ranked (lower bing higher numbered).
SELECT * from [TABLE] tb
LEFT JOIN Status_Precedence sp ON tb.Status = sp.Status
WHERE sp.Rank = (SELECT MIN(sp2.rank)
FROM[Table] tb2
LEFT JOIN Status_Precedence sp2 ON tb2.Status = sp2.Status
WHERE tb.Status = tb2.Status)
order by tb.[name]