I have a table whose structure is as follows
╔════════╦══════════╦════════════╗
║ app_id ║ app_name ║ categoryId ║
╠════════╬══════════╬════════════╣
║ 1200 ║ A ║ B ║
║ 1200 ║ A ║ C ║
║ 1200 ║ A ║ D ║
║ 1201 ║ E ║ F ║
║ 1201 ║ E ║ G ║
╚════════╩══════════╩════════════╝
Now I have 1600 such data. What I am trying to get is, a query to fetch data till the number of distinct appids reaches 200. After 200 is reached it should no longer fetch the rest of the data. I tried count(distinct(app_id)) but that doesn't seem to work the way I think. I am really struck here and it is a major performance issue. Any help is much appreciated. Thanks in advance.
You can try like this:
SELECT app_id
FROM myTable
GROUP BY app_id
HAVING COUNT(distinct app_id) < 200;
If what you want is
a query to fetch data till the number of distinct appids reaches 200
then you can use variables to implement this:
SELECT app_id, app_name, categoryId
FROM (
SELECT app_id, app_name, categoryId,
#appIDcnt := IF (#appID = app_id,
IF(#appID := app_id, #appIDcnt, #appIDcnt),
IF(#appID := app_id, #appIDcnt+1, #appIDcnt+1)) AS cnt
FROM mytable
CROSS JOIN (SELECT #appID := 0, #appIDcnt := 0) AS vars
ORDER BY app_id ) AS t
WHERE t.cnt <= 200
In the above query #appIDcnt variable is used to count distinct app_id values. The query fetches table data until #appIDcnt value reaches 200.
Demo here
use limit it will return the first 200 results only.
SELECT DISTINCT ap_id FROM appTable LIMIT 200
and then if you need to get the next 200 then use offset 200 which will start with row 201
SELECT DISTINCT ap_id FROM ap_Table LIMIT 200 OFFSET 200
Related
I have a table similar to
╔═════════════════════════════════════╗
║ id type report_id state ║
╠═════════════════════════════════════╣
║ 1 dc 122 pending ║
║ 2 dc 123 pending ║
║ 3 dc 123 approved ║
║ 4 dc 123 pending ║
║ 5 dc 123 approved ║
║ 6 bb 123 pending ║
║ 7 dc 123 pending ║
║ 8 dc 124 pending ║
║ 9 dc 125 pending ║
╚═════════════════════════════════════╝
I am trying to fetch the last report_id by type where state is pending
so results I would want are
122 (id 1 -- dc)
123 (id 6 -- bb)
123 (id 7 -- dc)
124 (id 8 -- dc)
125 (id 9 -- dc)
Right now I am fetching all, then running 3 loops on the array... I know there is a way to either join or perform an outer query to get it without the loops, any input on how i would word it?
I ran a query on a test database (15 records) and it worked there, but hangs on the live database (40k records)
SELECT report_id, type, state
FROM histories
WHERE id IN (
SELECT MAX(id) FROM histories
GROUP BY report_id
)
AND state <> 'approved'
For this, the sub-query executes fine and gives me proper results, the main query will give me results if I extract the sub-query, but combine them and it hangs...
Tested on ta SQL (not MySQL) database on a local machine with a limited data-set
I think you just want a group by with a filter:
select report_id, type, max(id)
from table t
where state = 'pending'
group by report_id, type;
Something like
SELECT report_id, MAX(id), type
FROM table_name
WHERE state = 'pending'
GROUP BY report_id, type
ORDER BY report_id
where table_name is your tables name. It is difficult to tell what you want from the results in your question.
What I did was this
take the sub-query and run it
SELECT MAX(id) FROM histories
GROUP BY report_id
... store as $id_array
then take the result and store it as CSV
$id_csv = implode(', ' $id_array);
then run my primary query
SELECT report_id, type, state
FROM histories
WHERE id IN ($id_csv)
AND state <> 'approved'
Not sure why it made a difference separating it, but it did the job (query takes about 3 seconds to run, I wish it were faster)
i have two tables for example:
BALANCE VS
╔══════╦══════╗ ╔══════╦═══════╗
║ V_ID ║ BAL ║ ║ V_ID ║ NAME ║
╠══════╬══════╣ ╠══════╬═══════╣
║ 1 ║ 1000 ║ ║ 1 ║ Carl ║
║ 1 ║ 500 ║ ║ 2 ║ Peter ║
║ 1 ║ -200 ║ ╚══════╩═══════╝
║ 2 ║ 350 ║
║ 2 ║ 1000 ║
╚══════╩══════╝
Now i've done a query like:
select
NAME,sum(BAL)
from VS,BALANCE
where VS.V_ID = BALANCE.V_ID
group by NAME
And the result is:
╔═══════╦══════╗
║ NAME ║ BAL ║
╠═══════╬══════╣
║ Carl ║ 1300 ║
║ Peter ║ 1350 ║
╚═══════╩══════╝
But i'd like to know how its done without the ´group by´ clause. Something like a subquery.
I tried different things but i cant figure out how it would work. I always end with results like all the values summed up into one row or results like the above one but without grouping.
may be anyone could help me
greetings
edit:forgot sum()
To get your current SQL to work using GROUP BY you would need the following (ie the SUM aggregate function):-
select NAME, SUM(BAL)
from VS, BALANCE
WHERE VS.V_ID = BALANCE.V_ID
group by NAME
Note that this is just your original SQL minimally modified to work and it still uses the implicit join you coded. Implicit joins should generally be avoided and better to use explicit INNER JOIN....ON syntax:-
select NAME, SUM(BAL)
from VS
INNER JOIN BALANCE
ON VS.V_ID = BALANCE.V_ID
group by NAME
If you really want to avoid the GROUP BY then it is possible using a sub query, but is likely to be slower (as it effectively has to perform an extra query for every row tha main query returns):-
select NAME, (SELECT SUM(BAL) FROM BALANCE WHERE BALANCE.V_ID = VS.V_ID)
from VS
EDIT, in response to your comment on sub queries.
Correlated sub queries effectively force MySQL to get a result set, and then for each row on the result set to perform another query. Most of the time they are used to get an aggregate value (such as the max value of a field related to a row on the returned row, but where GROUP BY on the main query would not be viable).
For example if you had a list of comments for a user, but on each row you wanted to know the date of the latest comment from that user you might do the following:-
SELECT users.user_name, comments.comment_date, (SELECT MAX(comment_date) FROM comments WHERE comments.user_id = users.id) AS latest_comment_date
FROM users
INNER JOIN comments
ON users.id = comments.user_id
This could be written to do a non correlated sub query using GROUP BY which is then joined:-
SELECT users.user_name, comments.comment_date, latest_comment_date
FROM users
INNER JOIN comments
ON users.id = comments.user_id
INNER JOIN
(
SELECT user_id, MAX(comment_date) AS latest_comment_date
FROM comments
GROUP BY user_id
) sub1
ON users.id = sub1.user_id
If you are dealing with a large number of records on users this would likely be faster.
However if you were only dealing with a tiny number of records on users (and determining that number was quite complex), getting ALL the max comment dates would be an unnecessary overhead, and it forces a join against a sub query which isn't likely to use indexes.
Try joining tables:
select NAME,BAL from VS JOIN BALANCE ON VS.V_ID = BALANCE.V_ID
Will return
NAME | BAL
-------------
Carl | 1000
Carl | 500
Carl | -200
Peter| 350
Peter| 1000
To get sum of BAL, you have to use GROUP BY, otherwise you will get SUM of all rows
Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
Questions asking for code must demonstrate a minimal understanding of the problem being solved. Include attempted solutions, why they didn't work, and the expected results. See also: Stack Overflow question checklist
Closed 9 years ago.
Improve this question
I have a table like this:
╔═══════════════════════╗
║ id name spent ║
╠═══════════════════════╣
║ 1 John 1000 ║
║ 2 Bob 2000 ║
║ 3 Richard 5000 ║
║ 4 Jane 2000 ║
║ 5 Anthony 2500 ║
╚═══════════════════════╝
I'd like to retrieve a row and rank the spent column like this
SELECT name,
spent
FROM table
WHERE id = 5 ;
and the desired result be something like this:
╔══════════════════════╗
║ name spent ║
╠══════════════════════╣
║ Anthony 2500 (2nd) ║
╚══════════════════════╝
That is, Anthony is the second who spent most (after Richard's 5000)
and if I wanted to order by who spent less it would be something like this
╔══════════════════════╗
║ name spent ║
╠══════════════════════╣
║ Anthony 2500 (4th) ║
╚══════════════════════╝
Here is the solution:
Order by who spent less
SELECT id, name, group_concat(spent,' (', rank,')') as t from (
SELECT id, name, spent, FIND_IN_SET( spent, (
SELECT GROUP_CONCAT( spent
ORDER BY spent)
FROM t1 )
) AS rank
FROM t1) as y
where id = 5
group by id, name
order by spent;
SQL Fiddle
Order By who spent more
SELECT id, name, group_concat(spent,' (', rank,')') as t from (
SELECT id, name, spent, FIND_IN_SET( spent, (
SELECT GROUP_CONCAT( spent
ORDER BY spent DESC)
FROM t1 )
) AS rank
FROM t1) as y
where id = 5
group by id, name
order by spent;
SQL Fiddle
I work with mysql and I've never encountered such a great challenge.
I hope you can help..
I have 1 table called Reports:
ID SerialNumber Remain_Toner_Black
7099 Z5UEBJAC900002Y 37
7281 Z5UEBJAC900002Y 36
7331 Z5UEBJAC900002Y 100
7627 8Z37B1DQ100105N 58
7660 8Z37B1DQ100105N 57
5996 CND8DDM2FH 83
5971 CND8DDM2FH 83
7062 3960125290 0
7088 3960125290 93
7100 3960125290 100
Now I want to be able to select records from the table where Remain_Toner_Black is higher than Remain_Toner_Black of the previous row in the table with the same SerialNumber (by previous I mean lower ID with the same SerialNumber).
For the above records I want the results below:
ID SerialNumber Remain_Toner_Black_Before Remain_Toner_Black_After
7331 Z5UEBJAC900002Y 36 100
7088 3960125290 0 93
7100 3960125290 93 100
SELECT a.ID, a.SerialNumber,
b.Remain_Toner_Black BeforeCount,
a.Remain_Toner_Black AfterCount
FROM
(
SELECT A.ID,
A.SerialNumber,
A.Remain_Toner_Black,
(
SELECT COUNT(*)
FROM tableName c
WHERE c.SerialNumber = a.SerialNumber AND
c.ID <= a.ID) AS RowNumber
FROM TableName a
) a
INNER JOIN
(
SELECT A.ID,
A.SerialNumber,
A.Remain_Toner_Black,
(
SELECT COUNT(*)
FROM tableName c
WHERE c.SerialNumber = a.SerialNumber AND
c.ID <= a.ID) AS RowNumber
FROM TableName a
) b ON a.SerialNumber = b.SerialNumber AND
a.RowNumber = b.RowNumber + 1
WHERE b.Remain_Toner_Black < a.Remain_Toner_Black
SQLFiddle Demo
OUTPUT
╔══════╦═════════════════╦═════════════╦════════════╗
║ ID ║ SERIALNUMBER ║ BEFORECOUNT ║ AFTERCOUNT ║
╠══════╬═════════════════╬═════════════╬════════════╣
║ 7331 ║ Z5UEBJAC900002Y ║ 36 ║ 100 ║
║ 7088 ║ 3960125290 ║ 0 ║ 93 ║
║ 7100 ║ 3960125290 ║ 93 ║ 100 ║
╚══════╩═════════════════╩═════════════╩════════════╝
BRIEF EXPLANATION
What the query above does is it generates a sequential number which mimics ROW_NUMBER() on other RDBS for every SerialNumber ordered by ID in ascending order.
The two subquery is then joined via the SerialNumber and sequential number generated. On the generated number, the value on the first subquery must be equal to plus one of the value on the second subquery to get the number of toner on the next reord.
MySQL (or indeed most other RDBMS) doesn't easily allow cross-row comparisons.
To do this sort of query, you must either perform a very expensive join comparing one version of the table to several rows of another version of the table, or construct a complex expression using user variables.
For example (with user variables):
SELECT ID, SerialNumber, #x Remain_Toner_Before,
#x := Remain_Toner_Black AS Remain_Toner_After
FROM Reports, (SELECT #x := -4) x
WHERE Remain_Toner_Black > #x
AND SerialNumber = '3960125290'
ORDER BY ID;
(the -4 is from your comment to another answer)
A better solution is to do this with cursors or in your application code, where you need only do one pass and compare simple logic by using variables in the cursor or application code.
I am using MySQL, I have 50 records in employee table. I want to find the person with the 22nd highest salary.
Use LIMIT, specifying both an offset and a row count.
To get the 22nd ranked person in order of highest salary, do:
SELECT person
FROM employee
ORDER BY salary DESC
LIMIT 21, 1
Notice the use of 21 here. This is because the offset of the initial row (1st highest salary) is actually 0. Therefore the 22nd highest salary will actually be an offset of 21 (the 21st row in 0-based counting, or "skip 21 rows").
To get the person(s) with the 22nd highest salary, you will need one more level of indirection. Try:
SELECT person
FROM employee
WHERE salary = (
SELECT DISTINCT salary
FROM employee
ORDER BY salary DESC
LIMIT 21, 1
)
here's another one, considering you have duplicate salary number. I guess limit won't correct solve your case if you have some duplicates. Try something like this,
SELECT aa.*
FROM table1 aa
INNER JOIN
(
SELECT #row:=#row+1 rankNo,
a.Salary
FROM (SELECT DISTINCT Salary FROM table1) a,
(SELECT #row:=0) s
ORDER BY Salary DESC
) bb ON aa.Salary = bb.Salary AND
bb.rankNo = 2
SQLFiddle Demo
consider you have records like this,
CREATE TABLE Table1
(`EmpID` int, `Salary` int);
INSERT INTO Table1
(`EmpID`, `Salary`)
VALUES
(1, 10),
(2, 12), -- duplicate
(3, 11),
(4, 12), -- duplicate
(5, 14),
(6, 12); -- duplicate
╔═══════╦════════╗
║ EMPID ║ SALARY ║
╠═══════╬════════╣
║ 1 ║ 10 ║
║ 2 ║ 12 ║
║ 3 ║ 11 ║ -- you want to get this value (*2nd from the last value*)
║ 4 ║ 12 ║
║ 5 ║ 14 ║
║ 6 ║ 12 ║
╚═══════╩════════╝
SELECT MIN(salary) FROM (
SELECT DISTINCT salary FROM employee ORDER BY salary DESC LIMIT 22
) limited_salary
Just answered a similar question here: select all rows except the four most recent
In your case, you'll want to LIMIT to 1, and OFFSET to the 22 position.
LIMIT 21,1
How to find n'th highest value of a column?
Query to find nth max value of a column