Custom order in SQL - sql

We are querying database to retrieve data in following fashion
select a,b,...f from table1 where id in (6,33,1,78,2)
The result I got from query is in following order 1,2,6,33,78.
I want the result in same order (6,33,1,78,2). Is there any way to retrieve the data in same order.
EDIT
*I am using SQL 2008*

add this order by clause
order by case
when id = 6 then 1
when id = 33 then 2
when id = 1 then 3
when id = 78 then 4
when id = 2 then 5
end
If using MySQL you can do this
ORDER BY FIND_IN_SET(id, '6,33,1,78,2')

Using a Table Value Constructor:
SELECT a, b, ... f
FROM
table1
JOIN
( VALUES
(1, 6),
(2, 33),
(3, 1),
(4, 78),
(5, 2)
) AS ordering (position, id)
ON ordering.id = table1.id
ORDER BY position

I don't know the background, but usually I achieve this custom order in an additional orderIndex column. This way I can manually manage the order when inserting to the table and add this column to the ORDER BY clause of the default queries

If you use SQL Server you could use charindex.
select A, B
from Table1
where ID in (6,33,1,78,2)
order by charindex(','+cast(ID as varchar(10))+',', ',6,33,1,78,2,')

ugly solution:
select a,b,...f from table1 where id in 6
UNION
select a,b,...f from table1 where id in 33
and so on..
"better" solution:
add another column on your query and do case 6 then 0, case 33 then 1 and so on
select a,b,...f , case id when 6 then 0 when 33 then 1 <and so on> end
from table1 where ...
and then order by this new column

Related

sql multiple filter all conditions in a group

I have a table with 3 fields:
id order date
1 1 null
1 2 not null
1 3 null
2 1 null
2 2 null
2 3 null
2 4 not null
3 1 null
I need the "id" in which:
ALL the "order" in (1,2,3)
and
ALL the "date" is null (so it is id 2)
I've tried as follows:
where order in (1,2,3) and date is null
but it returns both id 2 and id 1 (I'm expecting id 2 only).
Thanks for helps.
ID 3 should be also included. It satisfies your condition.
SELECT distinct id
FROM tab1 aa
WHERE aa.order IN (1, 2, 3) AND aa.data IS NULL
AND NOT exists(SELECT 1
FROM tab1 bb
WHERE ((bb.order IN (1, 2, 3) AND bb.data IS NOT NULL)
OR
(bb.order NOT IN (1, 2, 3) AND bb.data IS NULL))
AND aa.id = bb.id);
If you don't want ID 2 cause it has order in ID 4, then relax the last condition in:
bb.order NOT IN (1, 2, 3)
without the check in the date.
If with
ALL the "order" in (1,2,3)
you mean that there should be an order for 1, an order for 2 and an order for 3, then you should add and exists in the query to check this, like
and exists (select 1 form tab1 cc where aa.id = cc.id and cc.order = 1 and cc.data is not null)
and so on.
You want a result per ID, so GROUP BY it. You are only interested in order 1, 2, and 3, so use a WHERE clause. You only want IDs with all three orders and no date set. You can check this after aggregation in the HAVING clause.
select id
from mytable
where "order" in (1,2,3)
group by id
having count(*) = 3 -- all three IDs
and count("date") = 0; -- no non-null date
Rextester demo: http://rextester.com/SEE91944
(I surmise the table's unique key is id + order. Otherwise you'd have to COUNT(DISTINCT "order") and maybe to check null dates differently. As both order and date are SQL words, I am using quotes on them. You should avoid such names.)
I'm not sure what database are you using so I tried to right a query that should work with most. Have a look:
select * from
(select
id,
SUM(case
when [order] = 1 and [date] is null then 1
when [order] = 2 and [date] is null then 1
when [order] = 3 and [date] is null then 1
else 0
end) score
from test
group by id) scores
where score = 3
http://sqlfiddle.com/#!18/e4334/9
Sorry but none of above solved my question.
I solved it using "where not exists" (excluding the unwanted)
thanks to you all for your efforts.
If I've correctly interpreted your question, the following SQL does the work.
It returns id values of records for which all order who have 1, 2 or 3 value have null value for the date field:
SELECT DISTINCT id
FROM t
WHERE
order IN (1, 2, 3) AND
date IS NULL AND
id NOT IN (
SELECT id
FROM t
WHERE
order IN (1, 2, 3) AND
date IS NOT NULL
)

sql select a field into 2 columns

I am trying to run below 2 queries on the same table and hoping to get results in 2 different columns.
Query 1: select ID as M from table where field = 1
returns:
1
2
3
Query 2: select ID as N from table where field = 2
returns:
4
5
6
My goal is to get
Column1 - Column2
-----------------
1 4
2 5
3 6
Any suggestions? I am using SQL Server 2008 R2
Thanks
There has to be a primary key to foreign key relationship to JOIN data between two tables.
That is the idea about relational algebra and normalization. Otherwise, the correlation of the data is meaningless.
http://en.wikipedia.org/wiki/Database_normalization
The CROSS JOIN will give you all possibilities. (1,4), (1,5), (1, 6) ... (3,6). I do not think that is what you want.
You can always use a ROW_NUMBER() OVER () function to generate a surrogate key in both tables. Order the data the way you want inside the OVER () clause. However, this is still not in any Normal form.
In short. Why do this?
Quick test database. Stores products from sporting goods and home goods using non-normal form.
The results of the SELECT do not mean anything.
-- Just play
use tempdb;
go
-- Drop table
if object_id('abnormal_form') > 0
drop table abnormal_form
go
-- Create table
create table abnormal_form
(
Id int,
Category int,
Name varchar(50)
);
-- Load store products
insert into abnormal_form values
(1, 1, 'Bike'),
(2, 1, 'Bat'),
(3, 1, 'Ball'),
(4, 2, 'Pot'),
(5, 2, 'Pan'),
(6, 2, 'Spoon');
-- Sporting Goods
select * from abnormal_form where Category = 1
-- Home Goods
select * from abnormal_form where Category = 2
-- Does not mean anything to me
select Id1, Id2 from
(select ROW_NUMBER () OVER (ORDER BY ID) AS Rid1, Id as Id1
from abnormal_form where Category = 1) as s
join
(select ROW_NUMBER () OVER (ORDER BY ID) AS Rid2, Id as Id2
from abnormal_form where Category = 2) as h
on s.Rid1 = h.Rid2
We definitely need more information from the user.

MSSQL ORDER BY Passed List

I am using Lucene to perform queries on a subset of SQL data which returns me a scored list of RecordIDs, e.g. 11,4,5,25,30 .
I want to use this list to retrieve a set of results from the full SQL Table by RecordIDs.
So SELECT * FROM MyFullRecord
where RecordID in (11,5,3,25,30)
I would like the retrieved list to maintain the scored order.
I can do it by using an Order by like so;
ORDER BY (CASE WHEN RecordID = 11 THEN 0
WHEN RecordID = 5 THEN 1
WHEN RecordID = 3 THEN 2
WHEN RecordID = 25 THEN 3
WHEN RecordID = 30 THEN 4
END)
I am concerned with the loading of the server loading especially if I am passing long lists of RecordIDs. Does anyone have experience of this or how can I determine an optimum list length.
Are there any other ways to achieve this functionality in MSSQL?
Roger
You can record your list into a table or table variable with sorting priorities.
And then join your table with this sorting one.
DECLARE TABLE #tSortOrder (RecordID INT, SortOrder INT)
INSERT INTO #tSortOrder (RecordID, SortOrder)
SELECT 11, 1 UNION ALL
SELECT 5, 2 UNION ALL
SELECT 3, 3 UNION ALL
SELECT 25, 4 UNION ALL
SELECT 30, 5
SELECT *
FROM yourTable T
LEFT JOIN #tSortOrder S ON T.RecordID = S.RecordID
ORDER BY S.SortOrder
Instead of creating a searched order by statement, you could create an in memory table to join. It's easier on the eyes and definitely scales better.
SQL Statement
SELECT mfr.*
FROM MyFullRecord mfr
INNER JOIN (
SELECT *
FROM (VALUES (1, 11),
(2, 5),
(3, 3),
(4, 25),
(5, 30)
) q(ID, RecordID)
) q ON q.RecordID = mfr.RecordID
ORDER BY
q.ID
Look here for a fiddle
Something like:
SELECT * FROM MyFullRecord where RecordID in (11,5,3,25,30)
ORDER BY
CHARINDEX(','+CAST(RecordID AS varchar)+',',
','+'11,5,3,25,30'+',')
SQLFiddle demo

Select Condition Based on Multiple rows

I have a Table Like this:
TableA
----------------------------
ID - Name - PatID
1 A 10
2 B 10
3 A 11
4 A 12
5 B 13
I want to select All Such PatID Which has Name=A and Name = B.
So i should only get 10 as result.
What should be query for this?
You should be able to use the following query to get the result:
select patid
from tablea
where name in ('A', 'B')
group by patid
having count(distinct name) = 2;
See SQL Fiddle with Demo
If you need information from the A group and the B group you could also do it like this:
SELECT AGroup.ID AS AId, BGroup.ID AS BId
FROM TableA AGroup
JOIN TableB BGroup
ON AGroup.Name = 'A'
AND BGroup.Name = 'B'
AND AGroup.PatID = BGroup.PatID
This also retains duplicates if you have more than one entry, for Name = A and PatID = 10 for example.

Count(*) with 0 for boolean field

Let's say I have a boolean field in a database table and I want to get a tally of how many are 1 and how many are 0. Currently I am doing:
SELECT 'yes' AS result, COUNT( * ) AS num
FROM `table`
WHERE field = 1
UNION
SELECT 'no' AS result, COUNT( * ) AS num
FROM `table`
WHERE field = 0;
Is there an easier way to get the result so that even if there are no false values I will still get:
----------
|yes | 3 |
|no | 0 |
----------
One way would be to outer join onto a lookup table. So, create a lookup table that maps field values to names:
create table field_lookup (
field int,
description varchar(3)
)
and populate it
insert into field_lookup values (0, 'no')
insert into field_lookup values (1, 'yes')
now the next bit depends on your SQL vendor, the following has some Sybase (or SQL Server) specific bits (the outer join syntax and isnull to convert nulls to zero):
select description, isnull(num,0)
from (select field, count(*) num from `table` group by field) d, field_lookup fl
where d.field =* fl.field
you are on the right track, but the first answer will not be correct. Here is a solution that will give you Yes and No even if there is no "No" in the table:
SELECT 'Yes', (SELECT COUNT(*) FROM Tablename WHERE Field <> 0)
UNION ALL
SELECT 'No', (SELECT COUNT(*) FROM tablename WHERE Field = 0)
Be aware that I've checked Yes as <> 0 because some front end systems that uses SQL Server as backend server, uses -1 and 1 as yes.
Regards
Arild
This will result in two columns:
SELECT SUM(field) AS yes, COUNT(*) - SUM(field) AS no FROM table
Because there aren't any existing values for false, if you want to see a summary value for it - you need to LEFT JOIN to a table or derived table/inline view that does. Assuming there's no TYPE_CODES table to lookup the values, use:
SELECT x.desc_value AS result,
COALESCE(COUNT(t.field), 0) AS num
FROM (SELECT 1 AS value, 'yes' AS desc_value
UNION ALL
SELECT 2, 'no') x
LEFT JOIN TABLE t ON t.field = x.value
GROUP BY x.desc_value
SELECT COUNT(*) count, field FROM table GROUP BY field;
Not exactly same output format, but it's the same data you get back.
If one of them has none, you won't get that rows back, but that should be easy enough to check for in your code.