At the moment to display the highest value in my query I am using:
ORDER BY Height DESC
) T
WHERE RowNum = 1
This displays the highest value, for example 10, But what if two entries are both of the same value 10.
How can I make it so it shows both of the joint highest values?
use in Oracle, use the rank analytic
select a, b
from (select a, b, rank() over (order by height desc) rnk
from your_table)
where rnk = 1;
One solution would be to use a CTE
Using a CTE
;WITH q AS (
SELECT MAX(Height) AS maxHeight
FROM YourTable
)
SELECT *
FROM YourTable
INNER JOIN q ON q.maxHeight = Yourtable.Height
or a plain where clause with a subselect
SELECT *
FROM YourTable
WHERE Height = (SELECT MAX(Height) FROM YourTable)
Personally, I prefer using a CTE as it doesn't clutter up the statement (well, not true in this simple case but in practice, I often find it far more readable than subselects).
This will do and it's every simple too,
Select height from table where height=(select max(height) from table)
here you have without subqueries, it's more complicated but it was funny to created.
select ifnull(#d,#d:=actor_id),actor_id,if(#d>actor_id,1,0)as t
from t1 having t=0 order by actor_id desc;
here is the example in my computer.
mysql> desc t1;
+-------------+----------------------+------+-----+---------------------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------------+----------------------+------+-----+---------------------+-------+
| actor_id | smallint(5) unsigned | NO | | 0 | |
| first_name | varchar(45) | NO | | NULL | |
| last_name | varchar(45) | NO | | NULL | |
| last_update | timestamp | NO | | 0000-00-00 00:00:00 | |
+-------------+----------------------+------+-----+---------------------+-------+
4 rows in set (0.00 sec)
mysql> select * From t1 order by actor_id desc limit 5;
+----------+------------+-----------+---------------------+
| actor_id | first_name | last_name | last_update |
+----------+------------+-----------+---------------------+
| 20001 | test | test | 2012-12-13 09:12:50 |
| 20001 | test | test | 2012-12-13 09:12:51 |
| 2000 | b | a | 0000-00-00 00:00:00 |
| 2000 | b | a | 0000-00-00 00:00:00 |
| 2000 | b | a | 0000-00-00 00:00:00 |
+----------+------------+-----------+---------------------+
5 rows in set (0.00 sec)
mysql> select ifnull(#d,#d:=actor_id),actor_id,if(#d>actor_id,1,0)as t
-> from t1 having t=0 order by actor_id desc;
+-------------------------+----------+---+
| ifnull(#d,#d:=actor_id) | actor_id | t |
+-------------------------+----------+---+
| 20001 | 20001 | 0 |
| 20001 | 20001 | 0 |
+-------------------------+----------+---+
2 rows in set (0.00 sec)
Related
The query works fine with any operator for multiple values for any comparison.
SELECT Name, ID
from tblABC
where ID = ANY (1,2,3,4,5 )
But when a subquery is used for any comparison a right parenthesis missing error occurs
SELECT Name, ID
from tblABC
where ID = ANY (select ID from tblXYZ where ROWNUM <= 10 order by ID desc )
The subquery just gives the top 10 recent id entries from the selected table. Should there be a conversion to number or missing condition in this query?
The reason is order by, which is not necessary as it is evaluated after count stopkey (which is rownum < <constant>).
select *
from table(dbms_xplan.display_cursor(format => 'BASIC +PREDICATE'));
| PLAN_TABLE_OUTPUT |
| :----------------------------------------------------------------------- |
| EXPLAINED SQL STATEMENT: |
| ------------------------ |
| select /*+ gather_plan_statistics */ * from t where rownum < 5 order by |
| 1 asc |
| |
| Plan hash value: 846588679 |
| |
| ------------------------------------ |
| | Id | Operation | Name | |
| ------------------------------------ |
| | 0 | SELECT STATEMENT | | |
| | 1 | SORT ORDER BY | | |
| |* 2 | COUNT STOPKEY | | |
| | 3 | TABLE ACCESS FULL| T | |
| ------------------------------------ |
| |
| Predicate Information (identified by operation id): |
| --------------------------------------------------- |
| |
| 2 - filter(ROWNUM<5) |
| |
If you are on Oracle 12C+, then you may use fetch first:
select *
from dual
where 1 = any(select l from t order by 1 asc fetch first 4 rows only)
| DUMMY |
| :---- |
| X |
Or row_number() for older versions:
select *
from dual
where 1 = any (
select l
from (
select l, row_number() over(order by l asc) as rn
from t
)
where rn < 5
)
| DUMMY |
| :---- |
| X |
db<>fiddle here
It is order by part. It is not supported within sub-queries like this.
Just remove it. You don't need it for comparison anyway.
SELECT Name, ID
from tblABC
where ID = ANY (select ID from tblXYZ where ROWNUM <= 10 )
You can use FETCH FIRST <n> ROWS ONLY instead of using the old ROWNUM in the subquery.
For example:
SELECT Name, ID
from tblABC
where ID = ANY (select ID
from tblXYZ
order by ID desc
fetch first 10 rows only)
See running example at db<>fiddle.
I need help with this SQL query. This is my table:
| id_list | name | date_created | date_updated |
|-----------|-----------|-----------------------|---------------------|
| 1 | Laundry | 2020-10-14 12:29:14 | 2020-10-15 08:04:10 |
| 2 | Food | 2020-10-14 12:38:43 | 2020-10-15 10:45:03 |
How can I select the row with the nearest date_updated? The output has to be like this:
| id_list | name | date_created | date_updated |
|-----------|-----------|-----------------------|---------------------|
| 2 | Food | 2020-10-14 12:38:43 | 2020-10-15 10:45:03 |
If you just want the "nearest" to the current time just use the max. This will return multiple rows in case of a tie.
SELECT *
FROM A_TABLE
WHERE date_updated =
( SELECT MAX(date_updated)
FROM A_TABLE
)
If you just the one latest row, then order by and limit are sufficient:
select t.*
from mytable t
order by date_updated desc
limit 1
If you want the row that is closest to the current date/time, whether in the past or in the future, then:
select t.*
from mytable t
order by abs(julianday() - julianday(date_updated))
limit 1
Given this table I want to retrieve for each different url the row with the maximum count. For this table the output should be: 'dell.html' 3, 'lenovo.html' 4, 'toshiba.html' 5
+----------------+-------+
| url | count |
+----------------+-------+
| 'dell.html' | 1 |
| 'dell.html' | 2 |
| 'dell.html' | 3 |
| 'lenovo.html' | 1 |
| 'lenovo.html' | 2 |
| 'lenovo.html' | 3 |
| 'lenovo.html' | 4 |
| 'toshiba.html' | 1 |
| 'toshiba.html' | 2 |
| 'toshiba.html' | 3 |
| 'toshiba.html' | 4 |
| 'toshiba.html' | 5 |
+----------------+-------+
What SQL query do I need to write to do this?
Try to use this query:
select url, max(count) as count
from table_name
group by url;
use aggregate function
select max(count) ,url from table_name group by url
From your comments it seems you need corelated subquery
select t1.* from table_name t1
where t1.count = (select max(count) from table_name t2 where t2.url=t1.url
)
If row_number support on yours sqllite version
then you can write query like below
select * from
(
select *,row_number() over(partition by url order by count desc) rn
from table_name
) a where a.rn=1
I'm looking for ways to count unique users that have a specific pkey and also the count of unique users who didn't have that pkey.
Here is a sample table:
userid | pkey | pvalue
------------------------------
U1 | x | vx
U1 | y | vy
U1 | z | vz
U2 | y | vy
U3 | z | vz
U4 | null | null
I get the expected results to get the unique users who has the pkey='y' and those who didn't using this query but turns out to be expensive:
WITH all_rows AS
( SELECT userid,
IF( pkey='y', pval, 'none' ) AS val,
SUM( IF(pkey='y',1,0) ) AS has_key
FROM some_table
GROUP BY userid, val)
SELECT val,
count(distinct(userid)) uniqs
FROM all_rows
WHERE has_key=1
GROUP BY val
UNION ALL
SELECT 'no_key_set' val,
count(distinct(userid)) uniqs
FROM all_rows a1 LEFT ANTI JOIN
all_rows a2 on (a1.userid = a2.userid and a2.has_key=1)
GROUP BY val;
Results:
val | uniqs
--------------------
vy | 2
no_key_set | 2
I'm looking to avoid using any temp tables, so any better ways this can be achieved?
Thanks!
By using EXPLAIN, you can observe that most of the cost is spent on doing excessive GROUP BY aggregations rather than on using subqueries in your original query.
Here is a straightforward implementation
WITH t1 AS (
SELECT pkey, COUNT(*) AS cnt
FROM table
WHERE pkey IS NOT NULL
GROUP BY pkey
), t2 AS (
SELECT COUNT(DISTINCT userid) AS total_cnt
FROM table
)
SELECT
CONCAT('no_', pkey) AS pkey,
(total_cnt - cnt) AS cnt
FROM t1, t2
UNION ALL
SELECT * FROM t1
t1 gets a table of unique user count per pkey
+------+-----+
| pkey | cnt |
+------+-----+
| x | 1 |
| z | 2 |
| y | 2 |
+------+-----+
t2 gets the number of total unique users
+-----------+
| total_cnt |
+-----------+
| 4 |
+-----------+
we can use the result from t2 to get the complement table of t1
+------+-----+
| pkey | cnt |
+------+-----+
| no_x | 3 |
| no_z | 2 |
| no_y | 2 |
+------+-----+
a final union of the two tables gives a result of
+------+-----+
| pkey | cnt |
+------+-----+
| no_x | 3 |
| no_z | 2 |
| no_y | 2 |
| x | 1 |
| z | 2 |
| y | 2 |
+------+-----+
I have a table like this one:
+----+---------+----------+
| id | group | value |
+----+---------+----------+
| 1 | GROUP A | 0.641028 |
| 2 | GROUP B | 0.946927 |
| 3 | GROUP A | 0.811552 |
| 4 | GROUP C | 0.216978 |
| 5 | GROUP A | 0.650232 |
+----+---------+----------+
If I perform the following query:
SELECT `id`, SUM(`value`) AS `sum` FROM `test` GROUP BY `group`;
I, obviously, get:
+----+-------------------+
| id | sum |
+----+-------------------+
| 1 | 2.10281205177307 |
| 2 | 0.946927309036255 |
| 4 | 0.216977506875992 |
+----+-------------------+
But I need a table like this one:
+----+-------------------+
| id | sum |
+----+-------------------+
| 1 | 2.10281205177307 |
| 2 | 0.946927309036255 |
| 3 | 2.10281205177307 |
| 4 | 0.216977506875992 |
| 5 | 2.10281205177307 |
+----+-------------------+
Where summed rows are explicitly repeated.
Is there a way to obtain this result without using multiple (nested) queries?
IT would depend on your SQL server, in Postgres/Oracle I'd use Window Functions. In MySQL... not possible afaik.
Perhaps you can fake it like this:
SELECT a.id, SUM(b.value) AS `sum`
FROM test AS a
JOIN test AS b ON a.`group` = b.`group`
GROUP BY a.id, b.`group`;
No there isn't AFAIK. You will have to use a join like
SELECT t.`id`, tsum.sum AS `sum`
FROM `test` as t GROUP BY `group`
JOIN (SELECT `id`, SUM(`value`) AS `sum` FROM `test` GROUP BY `group`) AS tsum
ON tsum.id = t.id