I have a table with 3 columns (id, name, code) and 10 rows. Some of the rows don't have a code so that column is empty for some. What I'm trying to accomplish is SELECT the rows with code column not empty first ordered by last inserted followed by all rows with code column empty ordered by last inserted.
I have tried
(SELECT * from tablename WHERE code <> '' ORDER BY ID DESC) UNION
(SELECT * from tablename WHERE code = '' ORDER BY ID DESC)
The UNION works but the order does not. I have read here about other questions and found out adding ORDER BY like I added will not work and I should add it at the end but that would not help me accomplish what I want and will mix rows that have a code with rows that don't.
Is there a way to succeed with what I'm looking for?
I think you just need to put your sort logic in the ORDER BY clause
SELECT id, name, code
FROM tablename
ORDER BY code = '', ID desc;
Try this:
SELECT * FROM
(
(SELECT * from tablename WHERE code <> '' ORDER BY ID DESC)
UNION
(SELECT * from tablename WHERE code = '' ORDER BY ID DESC)
)tab ORDER BY ID DESC;
Or
SELECT * from tablename ORDER BY code DESC,ID DESC
Change ASC/DESC as per you want it to show
Related
I have this very simple table:
CREATE TABLE MyTable
(
Id INT(6) PRIMARY KEY,
Name VARCHAR(200) /* NOT UNIQUE */
);
If I want the Name(s) that is(are) the most frequent and the corresponding count(s), I can neither do this
SELECT Name, total
FROM table2
WHERE total = (SELECT MAX(total) FROM (SELECT Name, COUNT(*) AS total
FROM MyTable GROUP BY Name) table2);
nor this
SELECT Name, total
FROM (SELECT Name, COUNT(*) AS total FROM MyTable GROUP BY Name) table1
WHERE total = (SELECT MAX(total) FROM table1);
Also, (let's say the maximum count is 4) in the second proposition, if I replace the third line by
WHERE total = 4;
it works.
Why is that so?
Thanks a lot
You can try the following:
WITH stats as
(
SELECT Name
,COUNT(id) as count_ids
FROM MyTable
GROUP BY Name
)
SELECT Name
,count_ids
FROM
(
SELECT Name
,count_ids
,RANK() OVER(ORDER BY count_ids DESC) as rank_ -- this ranks all names
FROM stats
) s
WHERE rank_ = 1 -- the most popular ```
This should work in TSQL.
Your queries can't be executed because "total" is no column in your table. It's not sufficient to have it within a sub query, you also have to make sure the sub query will be executed, produces the desired result and then you can use this.
You should also consider to use a window function like proposed in Dimi's answer.
The advantage of such a function is that it can be much easier to read.
But you need to be careful since such functions often differ depending on the DB type.
If you want to go your way with a sub query, you can do something like this:
SELECT name, COUNT(name) AS total FROM myTable
GROUP BY name
HAVING COUNT(name) =
(SELECT MAX(sub.total) AS highestCount FROM
(SELECT Name, COUNT(*) AS total
FROM MyTable GROUP BY Name) sub);
I created a fiddle example which shows both queries mentioned here will produce the same and correct result:
db<>fiddle
What is the simplest SQL query to find the second largest integer value in a specific column?
There are maybe duplicate values in the column.
SELECT MAX( col )
FROM table
WHERE col < ( SELECT MAX( col )
FROM table )
SELECT MAX(col)
FROM table
WHERE col NOT IN ( SELECT MAX(col)
FROM table
);
In T-Sql there are two ways:
--filter out the max
select max( col )
from [table]
where col < (
select max( col )
from [table] )
--sort top two then bottom one
select top 1 col
from (
select top 2 col
from [table]
order by col) topTwo
order by col desc
In Microsoft SQL the first way is twice as fast as the second, even if the column in question is clustered.
This is because the sort operation is relatively slow compared to the table or index scan that the max aggregation uses.
Alternatively, in Microsoft SQL 2005 and above you can use the ROW_NUMBER() function:
select col
from (
select ROW_NUMBER() over (order by col asc) as 'rowNum', col
from [table] ) withRowNum
where rowNum = 2
I see both some SQL Server specific and some MySQL specific solutions here, so you might want to clarify which database you need. Though if I had to guess I'd say SQL Server since this is trivial in MySQL.
I also see some solutions that won't work because they fail to take into account the possibility for duplicates, so be careful which ones you accept. Finally, I see a few that will work but that will make two complete scans of the table. You want to make sure the 2nd scan is only looking at 2 values.
SQL Server (pre-2012):
SELECT MIN([column]) AS [column]
FROM (
SELECT TOP 2 [column]
FROM [Table]
GROUP BY [column]
ORDER BY [column] DESC
) a
MySQL:
SELECT `column`
FROM `table`
GROUP BY `column`
ORDER BY `column` DESC
LIMIT 1,1
Update:
SQL Server 2012 now supports a much cleaner (and standard) OFFSET/FETCH syntax:
SELECT [column]
FROM [Table]
GROUP BY [column]
ORDER BY [column] DESC
OFFSET 1 ROWS
FETCH NEXT 1 ROWS ONLY;
I suppose you can do something like:
SELECT *
FROM Table
ORDER BY NumericalColumn DESC
LIMIT 1 OFFSET 1
or
SELECT *
FROM Table ORDER BY NumericalColumn DESC
LIMIT (1, 1)
depending on your database server. Hint: SQL Server doesn't do LIMIT.
The easiest would be to get the second value from this result set in the application:
SELECT DISTINCT value
FROM Table
ORDER BY value DESC
LIMIT 2
But if you must select the second value using SQL, how about:
SELECT MIN(value)
FROM ( SELECT DISTINCT value
FROM Table
ORDER BY value DESC
LIMIT 2
) AS t
you can find the second largest value of column by using the following query
SELECT *
FROM TableName a
WHERE
2 = (SELECT count(DISTINCT(b.ColumnName))
FROM TableName b WHERE
a.ColumnName <= b.ColumnName);
you can find more details on the following link
http://www.abhishekbpatel.com/2012/12/how-to-get-nth-maximum-and-minimun.html
MSSQL
SELECT *
FROM [Users]
order by UserId desc OFFSET 1 ROW
FETCH NEXT 1 ROW ONLY;
MySQL
SELECT *
FROM Users
order by UserId desc LIMIT 1 OFFSET 1
No need of sub queries ... just skip one row and select second rows after order by descending
A very simple query to find the second largest value
SELECT `Column`
FROM `Table`
ORDER BY `Column` DESC
LIMIT 1,1;
SELECT MAX(Salary)
FROM Employee
WHERE Salary NOT IN ( SELECT MAX(Salary)
FROM Employee
)
This query will return the maximum salary, from the result - which not contains maximum salary from overall table.
Old question I know, but this gave me a better exec plan:
SELECT TOP 1 LEAD(MAX (column)) OVER (ORDER BY column desc)
FROM TABLE
GROUP BY column
This is very simple code, you can try this :-
ex :
Table name = test
salary
1000
1500
1450
7500
MSSQL Code to get 2nd largest value
select salary from test order by salary desc offset 1 rows fetch next 1 rows only;
here 'offset 1 rows' means 2nd row of table and 'fetch next 1 rows only' is for show only that 1 row. if you dont use 'fetch next 1 rows only' then it shows all the rows from the second row.
Simplest of all
select sal
from salary
order by sal desc
limit 1 offset 1
select * from (select ROW_NUMBER() over (Order by Col_x desc) as Row, Col_1
from table_1)as table_new tn inner join table_1 t1
on tn.col_1 = t1.col_1
where row = 2
Hope this help to get the value for any row.....
Use this query.
SELECT MAX( colname )
FROM Tablename
where colname < (
SELECT MAX( colname )
FROM Tablename)
select min(sal) from emp where sal in
(select TOP 2 (sal) from emp order by sal desc)
Note
sal is col name
emp is table name
select col_name
from (
select dense_rank() over (order by col_name desc) as 'rank', col_name
from table_name ) withrank
where rank = 2
SELECT
*
FROM
table
WHERE
column < (SELECT max(columnq) FROM table)
ORDER BY
column DESC LIMIT 1
It is the most esiest way:
SELECT
Column name
FROM
Table name
ORDER BY
Column name DESC
LIMIT 1,1
As you mentioned duplicate values . In such case you may use DISTINCT and GROUP BY to find out second highest value
Here is a table
salary
:
GROUP BY
SELECT amount FROM salary
GROUP by amount
ORDER BY amount DESC
LIMIT 1 , 1
DISTINCT
SELECT DISTINCT amount
FROM salary
ORDER BY amount DESC
LIMIT 1 , 1
First portion of LIMIT = starting index
Second portion of LIMIT = how many value
Tom, believe this will fail when there is more than one value returned in select max([COLUMN_NAME]) from [TABLE_NAME] section. i.e. where there are more than 2 values in the data set.
Slight modification to your query will work -
select max([COLUMN_NAME])
from [TABLE_NAME]
where [COLUMN_NAME] IN ( select max([COLUMN_NAME])
from [TABLE_NAME]
)
select max(COL_NAME)
from TABLE_NAME
where COL_NAME in ( select COL_NAME
from TABLE_NAME
where COL_NAME < ( select max(COL_NAME)
from TABLE_NAME
)
);
subquery returns all values other than the largest.
select the max value from the returned list.
This is an another way to find the second largest value of a column.Consider the table 'Student' and column 'Age'.Then the query is,
select top 1 Age
from Student
where Age in ( select distinct top 2 Age
from Student order by Age desc
) order by Age asc
select age
from student
group by id having age< ( select max(age)
from student
)
order by age
limit 1
SELECT MAX(sal)
FROM emp
WHERE sal NOT IN ( SELECT top 3 sal
FROM emp order by sal desc
)
this will return the third highest sal of emp table
select max(column_name)
from table_name
where column_name not in ( select max(column_name)
from table_name
);
not in is a condition that exclude the highest value of column_name.
Reference : programmer interview
Something like this? I haven't tested it, though:
select top 1 x
from (
select top 2 distinct x
from y
order by x desc
) z
order by x
See How to select the nth row in a SQL database table?.
Sybase SQL Anywhere supports:
SELECT TOP 1 START AT 2 value from table ORDER BY value
Using a correlated query:
Select * from x x1 where 1 = (select count(*) from x where x1.a < a)
select * from emp e where 3>=(select count(distinct salary)
from emp where s.salary<=salary)
This query selects the maximum three salaries. If two emp get the same salary this does not affect the query.
I'm trying to include select statement in the then of case statement but the output is not as expected. I know there is different method to do this but can it be done the way i'm trying to do.
Using the following example data:
create table example(name varchar(10));
insert into example values
('abc'),('bcd'),('xyz');
I have tried this query (here is the fiddle):
select
case when ((select * from example where name='abc')>=1)
then (select * from example where name='abc')
else (select count(*) from example)
end
from example
But it outputs
3
3
3
Expected output if name='abc' exist
name
abc
if not the count(*)
Thanks in advance
Your subquery in the example is (select * from example where name='abc') which is a result set, not a scalar value. Currently it "works" because it is comparing the only column in the table to the value 1 but if you had more than one column in the table it would error out. Perhaps you intended (select count(*) from example where name='abc')?
Similarly, the THEN clause in a case can only be used to provide a single column value. In order to do this, perhaps you meant the following:
select
case when exists (select * from example where name='abc')
then (select name from example where name='abc')
else (select count(*) from example)
end
from example
But even here you will get three rows and there is no correlation between the rows in example and the result set, so I am not really sure what you're trying to do. I imagine there is a higher purpose though so I will leave it at that.
This should do the trick
select distinct
case when ((select count(name) from example where name='abc')>=1)
then (select * from example where name='abc')
else (select count(*) from example)
end
from example
Let me know if it works.
Point 1:
For the query, you are trying, the from example in the last will cause to loop through all the records and fetch all the records. To restrict that, you have to remove that.
Point 2:
You can't combine multi row select * in a true condition with a single row count(*) in a false condition. You should limit to select a single row.
Example:
select
case when ( select count(*) from example where name='abc' ) >= 1
then ( select * from example where name='abc' limit 1 )
else ( select count(*) from example )
end as name
No need to bother with the complex queries.
SELECT COUNT(*) AS ct
FROM example
GROUP BY name = 'abc'
ORDER BY name = 'abc' DESC
LIMIT 1;
If you really want to use CASE just for the sake of using it:
SELECT
CASE name
WHEN 'abc' THEN 'abc'
ELSE 'others'
END AS name, COUNT(*) AS ct
FROM example
GROUP BY name = 'abc'
ORDER BY name = 'abc' DESC
LIMIT 1;
Try below query, which will work even you enter a second duplicate row as value 'abc'. Mostly above suggested queries will not work as you enter this duplicate row while as per your query condition (>=1), there can be multiple rows for name as 'abc'.
SELECT
CASE WHEN b.cnt>=1
THEN a.name
ELSE (SELECT COUNT(*) FROM EXAMPLE)
END
FROM (SELECT DISTINCT NAME FROM EXAMPLE WHERE NAME='abc') a
JOIN (SELECT NAME,COUNT(*) AS cnt FROM EXAMPLE WHERE NAME='abc') b
ON a.name=b.name
I have a table :
ID | time
1 | 300
1 | 100
1 | 200
2 | 200
2 | 500
I want to get 2nd row for every ID
I know that I can get 1st row as
select ID,time from T group by ID;
But I don't know about how to get 2nd row for every ID.
I know about limit and offset clause in mysql, but can't figure out how to use them here.
How can I do it ?
EDIT : Actually, time is not ordered. I forgot to specify that. I have made an edit in the table.
i have just an idee how to make it but i couldnt fix it , maybe you can fix it. any suggest is appreciated to correct my query
first this to select the first row of each id.
SELECT min(id) id
FROM TableName t2
group by id
then select the min(id) which are not in the first query to select to min(id) (which is second row)
like that
SELECT min(id) id ,time
FROM TableName
WHERE id NOT IN (
SELECT min(id) id
FROM TableName
GROUP BY id
)
GROUP BY id
** as i said its just suggest . it returns me 0 values.if u fix it let me edit my post to be helpful
here a demo
SELECT ID, MAX(time) time
FROM
(
select ID, Time
from TableName a
where
(
select count(*)
from TableName as f
where f.ID = a.ID and f.time <= a.time
) <= 2
) s
GROUP BY ID
SQLFiddle Demo
SELECT x.*
FROM test x
JOIN test y
ON y.id = x.id
AND y.time >= x.time
GROUP
BY id,time
HAVING COUNT(*) = n;
Note that any entries with less than n results will be omitted
You cannot do this with the tables that you have. You could make a valiant attempt with:
select id, time
from (select id, time
from t
group by t
) t
where not exists (select 1 from t t2 where t2.id = t.id and t2.time = t.time)
group by id
That is, attempt to filter out the first row.
The reason this is not possible is because tables are inherently unordered, so there is not real definition of "second" in your tables. This gives the SQL engine the opportunity to rearrange the rows as it sees fit during processing -- which can result in great performance gains.
Even the construct that you are using:
select id, time
from t
group by id
is not guaranteed to return time from the first row. This is a (mis)feature of MySQL called Hidden Columns. It is really only intended for the case where all the values are the same. I will admit that in practice it seems to get the value from the first row, but you cannot guarantee that.
Probably your best solution is to select the data into a new table that has an auto-incrementing column:
create table newtable (
autoid int auto_increment,
id int,
time int
);
insert into newtable(id, time)
select id, time from t;
In practice, this will probably keep the same order as the original table, and you can then use the autoid to get the second row. I want to emphasize, though, the "in practice". There is no guarantee that the values are in the correct order, but they probably will be.
I have this mysql query which works in getting the specific data by specified date;
SELECT id FROM mytable WHERE DAY(idate)='11' AND MONTH(idate)='01' AND YEAR(idate)='2013' GROUP BY id
now i want to get the data from the date specified and the data outside the date specified, I've tried this query and returns zero results;
SELECT id FROM mytable WHERE DAY(idate)='11' AND DAY(idate)<>'11' AND MONTH(idate)='01' AND YEAR(idate)='2013' GROUP BY id
Your SQL:
SELECT id FROM mytable WHERE DAY(idate)='11' AND DAY(idate)<>'11'
AND MONTH(idate)='01' AND YEAR(idate)='2013' GROUP BY id
is saying "Select the id for the rows from mytable where the day is both equal to 11 and also not equal to 11..."
This is an impossible situation, hence you're getting nothing.
What you actually want is "Select the id for the rows from mytable where the day is equal to 11 as well as the rows where date is not equal to 11...", I think. This is the same as "Select the id for the rows from mytable regardless of the value of the date..." or:
SELECT id FROM mytable WHERE MONTH(idate)='01' AND YEAR(idate)='2013' GROUP BY id
Try OR instead of AND:
SELECT id
FROM mytable t1
WHERE DAY(idate)<>'11'
OR ( DAY(idate) = '11'
AND MONTH(idate)='01'
AND YEAR(idate)='2013'
)
GROUP BY id
you can use your first query and subtract from the queried table, or you can fix your query (read about De-Morgan's laws):
SELECT id
FROM mytable
WHERE DAY(idate)<>'11' OR MONTH(idate)<>'01' OR MONTH(idate)='01' OR YEAR(idate)='2013'
GROUP BY id
Your query at the moment basically has this as a WHERE clause:
where 1 = 1
and 1 <> 1
Obviously both cannot be true. Similarly your filters on DAY(idate) are mutually exclusive. It is difficult to understand exactly what you're trying to achieve. Perhaps you should jyst remove the tests on DAY() altogether?
SELECT id
FROM mytable
WHERE MONTH(idate)='01'
AND YEAR(idate)='2013'
GROUP BY id