How to change a UNION to a IN clause? - sql

I need to get a maximum of 3 distinct records from the same table, so currently I'm doing:
SELECT 1, mycolumn FROM mytable WHERE id = #firstId
UNION ALL
SELECT 2, mycolumn FROM mytable WHERE id = #secondId
UNION ALL
SELECT 3, mycolumn FROM mytable WHERE id = #thirdId
The actual SELECT part contains over 20 columns and the FROM part contains a number of JOINs. The first column is a constant and is always fixed depending on the record. I don't know how many records might return. It could be anything from 0 to 3 records.
Is it possible to change the above query so that it uses IN like this:
SELECT ???, mycolumn FROM mytable WHERE id IN (#firstId, #secondId, #thirdId)
But how do I explicitly map each record to the fixed constant if I use IN?

You may use a CASE expression here with a single query:
SELECT
CASE id WHEN #firstId THEN 1
WHEN #secondId THEN 2
WHEN #thirdId THEN 3 END AS val,
mycolumn
FROM mytable
WHERE
id IN (#firstId, #secondId, #thirdId);
If you wish to also order by the computed column, then add ORDER BY val to the end of the above query.

You can use CASE like following.
SELECT
CASE
WHEN id= #firstId THEN 1
WHEN id=#secondId THEN 2
ELSE 3
END AS rn,
mycolumn
FROM mytable
WHERE id IN (#firstId,
#secondId,
#thirdId)
Another approach can be using DENSE_RANK if you have one record for each provided id and #firstId, #secondId & #thirdId are in ascending order.
SELECT DENSE_RANK()
OVER(
ORDER BY id) rn,
mycolumn
FROM mytable
WHERE id IN ( #firstId, #secondId, #thirdId )

I would recommend a table-valued constructor for this purpose:
select v.outputnum, my_column
from mytable t join
(values (#firstid, 1),
(#secondid, 2),
(#thirdid, 3)
) v(id, outputnum)
on t.id = v.id
order by v.outputnum;
I think this is simpler than other versions, because the list of ids is only present once in the query -- so no danger of different parts of the query getting out of sync.

Related

How to Always select a certain value 1st sql

say i have a TABLE with the values
1,2,2,3,4 and ALL
in the SAME column
and I then
SELECT DISTINCT
value
FROM table
How would I go about always selecting 'All' 1st ?
or atleast ordering it that 'All' is 1st.
NOTE: The column is a VARCHAR(x)
EDIT:
SELECT DISTINCT
Strategy
FROM #Strategy
ORDER BY case when Strategy = 'All' then 0 else 1 end,
Strategy DESC
This is my query currently
You chose correct keyword (DISTINCT) and correct expression (ORDER BY CASE WHEN ... END) for each individual question. The trick is to solve the questions one by one instead of once.
SELECT *
FROM
(
SELECT DISTINCT T1.*
FROM (VALUES ('1'), ('2'), ('2'), ('3'), ('4'), ('ALL')) AS T1(Strategy)
) AS T2
ORDER BY CASE WHEN Strategy = 'ALL' THEN 0 ELSE 1 END, Strategy;
In this instance just use:
SELECT DISTINCT Value FROM TABLE ORDER BY Value Desc
Please try this.
Declare #table table (id varchar(max))
Insert into #table values ('1'),('2'),('2'),('All'),('3'),('4')
select * from #table
--select * from #table order by id
select * from #table order by case when id = 'All' then 0 else id end
Another twist, suppose you have 2 varchar entry still this logic work as
Declare #table table (id varchar(max))
Insert into #table values ('1'),('2'),('2'),('All'),('3'),('4'),('Select')
select * from #table
select * from #table order by id
select * from #table order by case when id in ( 'All' , 'Select') then 0 else id end
You can use GROUP BY (instead of DISTINCT) with #jarlh 's suggestion for the ORDER BY clause in the comments above (tweaked ever so slightly).
SELECT
Strategy
FROM
#Strategy
GROUP BY
Strategy
ORDER BY
CASE WHEN Strategy = 'All' THEN 0 ELSE Strategy END
Or by continuing to use DISTINCT you can move the CASE statement to the SELECT clause to create a new column to use in the ORDER BY clause:
SELECT DISTINCT
Strategy
,CASE WHEN Strategy = 'All' THEN 0 ELSE Strategy END AS SortOrder
FROM
#Strategy
ORDER BY
SortOrder
Or if the order of the subsequent items doesn't matter just keep it simple as #ChrisChurch suggests.

Counting the rows of a column where the value of a different column is 1

I am using a select count distinct to count the number of records in a column. However, I only want to count the records where the value of a different column is 1.
So my table looks a bit like this:
Name------Type
abc---------1
def----------2
ghi----------2
jkl-----------1
mno--------1
and I want the query only to count abc, jkl and mno and thus return '3'.
I wasn't able to do this with the CASE function, because this only seems to work with conditions in the same column.
EDIT: Sorry, I should have added, I want to make a query that counts both types.
So the result should look more like:
1---3
2---2
SELECT COUNT(*)
FROM dbo.[table name]
WHERE [type] = 1;
If you want to return the counts by type:
SELECT [type], COUNT(*)
FROM dbo.[table name]
GROUP BY [type]
ORDER BY [type];
You should avoid using keywords like type as column names - you can avoid a lot of square brackets if you use a more specific, non-reserved word.
I think you'll want (assuming that you wouldn't want to count ('abc',1) twice if it is in your table twice):
select count(distinct name)
from mytable
where type = 1
EDIT: for getting all types
select type, count(distinct name)
from mytable
group by type
order by type
select count(1) from tbl where type = 1
;WITH MyTable (Name, [Type]) AS
(
SELECT 'abc', 1
UNION
SELECT 'def', 2
UNION
SELECT 'ghi', 2
UNION
SELECT 'jkl', 1
UNION
SELECT 'mno', 1
)
SELECT COUNT( DISTINCT Name)
FROM MyTable
WHERE [Type] = 1

Select DISTINCT, return entire row

I have a table with 10 columns.
I want to return all rows for which Col006 is distinct, but return all columns...
How can I do this?
if column 6 appears like this:
| Column 6 |
| item1 |
| item1 |
| item2 |
| item1 |
I want to return two rows, one of the records with item1 and the other with item2, along with all other columns.
In SQL Server 2005 and above:
;WITH q AS
(
SELECT *, ROW_NUMBER() OVER (PARTITION BY col6 ORDER BY id) rn
FROM mytable
)
SELECT *
FROM q
WHERE rn = 1
In SQL Server 2000, provided that you have a primary key column:
SELECT mt.*
FROM (
SELECT DISTINCT col6
FROM mytable
) mto
JOIN mytable mt
ON mt.id =
(
SELECT TOP 1 id
FROM mytable mti
WHERE mti.col6 = mto.col6
-- ORDER BY
-- id
-- Uncomment the lines above if the order matters
)
Update:
Check your database version and compatibility level:
SELECT ##VERSION
SELECT COMPATIBILITY_LEVEL
FROM sys.databases
WHERE name = DB_NAME()
The key word "DISTINCT" in SQL has the meaning of "unique value". When applied to a column in a query it will return as many rows from the result set as there are unique, different values for that column. As a consequence it creates a grouped result set, and values of other columns are random unless defined by other functions (such as max, min, average, etc.)
If you meant to say you want to return all rows for which Col006 has a specific value, then use the "where Col006 = value" clause.
If you meant to say you want to return all rows for which Col006 is different from all other values of Col006, then you still need to specify what that value is => see above.
If you want to say that the value of Col006 can only be evaluated once all rows have been retrieved, then use the "having Col006 = value" clause. This has the same effect as the "where" clause, but "where" gets applied when rows are retrieved from the raw tables, whereas "having" is applied once all other calculations have been made (i.e. aggregation functions have been run etc.) and just before the result set is returned to the user.
UPDATE:
After having seen your edit, I have to point out that if you use any of the other suggestions, you will end up with random values in all other 9 columns for the row that contains the value "item1" in Col006, due to the constraint further up in my post.
You can group on Col006 to get the distinct values, but then you have to decide what to do with the multiple records in each group.
You can use aggregates to pick a value from the records. Example:
select Col006, min(Col001), max(Col002)
from TheTable
group by Col006
order by Col006
If you want the values to come from a specific record in each group, you have to identify it somehow. Example of using Col002 to identify the record in each group:
select Col006, Col001, Col002
from TheTable t
inner join (
select Col006, min(Col002)
from TheTable
group by Col006
) x on t.Col006 = x.Col006 and t.Col002 = x.Col002
order by Col006
SELECT *
FROM (SELECT DISTINCT YourDistinctField FROM YourTable) AS A
CROSS APPLY
( SELECT TOP 1 * FROM YourTable B
WHERE B.YourDistinctField = A.YourDistinctField ) AS NewTableName
I tried the answers posted above with no luck... but this does the trick!
select * from yourTable where column6 in (select distinct column6 from yourTable);
SELECT *
FROM harvest
GROUP BY estimated_total;
You can use GROUP BY and MIN() to get more specific result.
Lets say that you have id as the primary_key.
And we want to get all the DISTINCT values for a column lets say estimated_total, And you also need one sample of complete row with each distinct value in SQL. Following query should do the trick.
SELECT *, min(id)
FROM harvest
GROUP BY estimated_total;
create table #temp
(C1 TINYINT,
C2 TINYINT,
C3 TINYINT,
C4 TINYINT,
C5 TINYINT,
C6 TINYINT)
INSERT INTO #temp
SELECT 1,1,1,1,1,6
UNION ALL SELECT 1,1,1,1,1,6
UNION ALL SELECT 3,1,1,1,1,3
UNION ALL SELECT 4,2,1,1,1,6
SELECT * FROM #temp
SELECT *
FROM(
SELECT ROW_NUMBER() OVER (PARTITION BY C6 Order by C1) ID,* FROM #temp
)T
WHERE ID = 1

SQL Server Top 1

In Microsoft SQL Server 2005 or above, I would like to get the first row, and if there is no matching row, then return a row with default values.
SELECT TOP 1 ID,Name
FROM TableName
UNION ALL
SELECT 0,''
ORDER BY ID DESC
This works, except that it returns two rows if there is data in the table, and 1 row if not.
I'd like it to always return 1 row.
I think it has something to do with EXISTS, but I'm not sure.
It would be something like:
SELECT TOP 1 * FROM Contact
WHERE EXISTS(select * from contact)
But if not EXISTS, then SELECT 0,''
What happens when the table is very full and you might want to specify which row of your top 1 to get, such as the first name? OMG Ponies' query will return the wrong answer in that case if you just change the ORDER BY clause. His query also costs about 8% more CPU than this modification (though it has equal reads)
SELECT TOP 1 *
FROM (
SELECT TOP 1 ID,Name
FROM TableName
ORDER BY Name
UNION ALL
SELECT 0,''
) X
ORDER BY ID DESC
The difference is that the inner query has a TOP 1 also, and which TOP 1 can be specified there (as shown).
Just for fun, this is another way to do it which performs very closely to the above query (-15ms to +30ms). While it's more complicated than necessary for such a simple query, it demonstrates a technique that I don't see other SQL folks using very often.
SELECT
ID = Coalesce(T.ID, 0),
Name = Coalesce(T.Name, '')
FROM
(SELECT 1) X (Num)
LEFT JOIN (
SELECT TOP 1 ID, Name
FROM TableName
ORDER BY ID DESC
) T ON 1 = 1 -- effective cross join but does not limit rows in the first table
Use:
SELECT TOP 1
x.id,
x.name
FROM (SELECT t.id,
t.name
FROM TABLENAME t
UNION ALL
SELECT 0,
'') x
ORDER BY id DESC
Using a CTE equivalent:
WITH query AS (
SELECT t.id,
t.name
FROM TABLENAME t
UNION ALL
SELECT 0,
'')
SELECT TOP 1
x.id,
x.name
FROM query x
ORDER BY x.id DESC
CREATE TABLE #sample(id INT, data VARCHAR(10))
SELECT TOP 1 id, data INTO #temp FROM #sample
IF ##ROWCOUNT = 0 INSERT INTO #temp VALUES (null, null)
SELECT * FROM #temp
put the top oustide of the UNION query
SELECT TOP 1 * FROM(
SELECT ID,Name
FROM TableName
UNION ALL
SELECT 0,''
) z
ORDER BY ID DESC
IF EXISTS ( SELECT TOP 1 ID, Name FROM TableName )
BEGIN
SELECT TOP 1 ID, Name FROM TableName
END
ELSE
BEGIN
--exists returned no rows
--send a default row
SELECT 0, ''
END

SQL: Retrieve value from a column that occurred least number of times

I have a table which have a single field. and it have a values like (3,7,9,11,7,11)
Now I want a query which will pick the value that occurred least number of times and if there is a tie with minimum occurrences then use the smallest number
In this case the answer will be 3.
Something like this:
SELECT TOP 1 COUNT(*), myField
FROM myTable
GROUP BY (myField)
ORDER BY COUNT(*) ASC
ADDITIONAL: And to taking into account the tie-breaker situation:
SELECT TOP 1 COUNT(*), myField
FROM myTable
GROUP BY (myField)
ORDER BY COUNT(*) ASC, myField ASC
In MySQL and PostgreSQL:
SELECT *
FROM (
SELECT field, COUNT(*) AS cnt
FROM mytable
GROUP BY
field
) q
ORDER BY
cnt, field
LIMIT 1
Assuming you're using SQL Server: if you have ties for the least frequent number, and you want all ties returned, then you could do something like this:
DECLARE #temp table (
count int,
myField int
)
INSERT #temp
SELECT COUNT(*), myField
FROM myTable
GROUP BY (myField)
DECLARE #minCount int
SELECT #minCount = MIN(count)
FROM #temp
SELECT count, myField
FROM #temp
WHERE count = #minCount