i am having two tables ss_test and ss_ceastore_config ss_test has field called store_id which maps to ss_ceastore_config id.
my ss_test contains servers entry which tells that which store it is using
so i am trying to find which store is used min times and its id.
i have below query written.
select id,
min(server_counts) as server_counts,
isalive
from (select ss_ceastore_config.id ,
count(server_id)as server_counts,
ss_ceastore_config.isalive
from ss_test
right join ss_ceastore_config
on ss_test.store_id = ss_ceastore_config.id
group by store_id
order by id) join_1
my inner query gives me proper result as below
id Ascending server_counts isalive
1 5 1
2 0 1
so i want to select below record from inner query output using min function
id Ascending server_counts isalive
2 0 1
but it gives unexpected result with my outer query as below
id server_counts isalive
1 0 1
why this so? why it is giving id 1 for server_counts 0?
how to fix this query?
select id,
server_counts,
isalive
from (select ss_ceastore_config.id ,
count(server_id)as server_counts,
ss_ceastore_config.isalive
from ss_test
right join ss_ceastore_config
on ss_test.store_id = ss_ceastore_config.id
group by store_id
order by id) join_1
order by server_counts asc
limit 1;
Your original query was not working because you were doing an aggregate SELECT using the MIN() function along with non-aggregate columns such as id and isalive. I believe that MySQL makes no guarantee about which id value it will return along with the minimum for that column.
My strategy is to return all rows in ascending order by server_counts, and then to SELECT only the first row (which is the minimum).
Related
I have this problem where I want to first select 8 elements from a mysql database ordering by id DESC.
Then I want to select another group of results (8 items), this time order by date DESC but the results here I want to ensure that they are not already on the fisrt query the one for ordering by id.
The data is in the same table just with different columns like id,name,date,.
So far I have tried writing different queries to get the data but the data contains some similar items of which that is what I don't want.
Here are the queries I have written;
this returns 8 items sorted by id DESC
SELECT name FROM person order by id DESC LIMIT 8;
this returns 8 items also but sorted by date DESC
SELECT name FROM person order by date DESC LIMIT 8;
the returned data contain duplicate items!
You could use a nested query, first select the first 8 id's, then select the first 8 records ordered by date, excluding those id's:
SELECT name FROM person
WHERE id NOT IN
(SELECT id FROM person order by id DESC LIMIT 8) AS exc
ORDER BY date DESC LIMIT 8
The first query should return the primary key for the table. If name is the key then so be it, but probably that id field is the better choice.
Then we can write the query like this:
SELECT p.name
FROM Person p
WHERE NOT EXISTS (
SELECT 1
FROM (SELECT id FROM Person ORDER BY id DESC LIMIT 8) p0
WHERE p0.id = p.id
)
ORDER BY p.date DESC
LIMIT 8;
We could also use an exclusion join which is usually slower, but in this case reduces one level of nesting so it might do better:
SELECT p.name
FROM Person p
LEFT JOIN (
SELECT id
FROM Person
ORDER BY id DESC
LIMIT 8
) p0 ON p0.id = p.id
WHERE p0.id is null
ORDER BY p.date DESC
LIMIT 8;
One other thing to keep in mind is MySQL is strict about what kinds of subquery can use the LIMIT keyword. Specifically, you need it to be a derived table. I know the exclusion join option should qualify, but I'm less sure of the NOT EXISTS() option.
Why not generate both resultsets with a single query? We can combine window functions, order by, and limit to generate a resultset containing the top 8 rows per id and the top 8 rows per date, while avoiding duplicates:
select *
from (
select p.*,
row_number() over(order by id desc) rn_id,
row_number() over(order by date desc) rn_dt
from person p
) p
order by case when rn_id <= 8 then rn_id else 9 end, rn_dt
limit 16
In the subquery, the window functions enumerate records by descending id and date. The outer query performs a conditional sort that puts the top 8 id first, and orders the rest of the records by descending date. All that is left to do is retain the top 16 results from the query. You don't need to worry about duplicates since the table is scanned only once.
Here is a small test case:
id
date
1
2022-11-11
2
2022-11-09
3
2022-11-05
4
2022-11-06
5
2022-11-07
6
2022-11-08
7
2022-11-10
For this sample data, and given a target of 3 + 3 records (instead of 8 + 8 in our code), the query returns:
id
date
rn_id
rn_dt
7
2022-11-10
1
2
6
2022-11-08
2
4
5
2022-11-07
3
5
1
2022-11-11
7
1
2
2022-11-09
6
3
4
2022-11-06
4
6
Typically, id 7, which has both the greatest id the second latest date, shows up in the first part of the resultset (the top 3 rows are sorted by descending id), but is not repeated in the second part.
Demo on DB fiddle
Can anyone please help to get last record from the group.enter image description here
I think you need this:
select * from t where col = 85 order by id desc limit 1
According to your comment, this should get last records for every group: (this assumes that id is unique and "last record" means record, with highest id)
select t.* from t
inner join (select max(id) as maxid from t group by col) s
on t.id = s.maxid
To fetch the 1 row from mysql use 'limit' keyword.
MySQL supports the LIMIT clause to select a limited number of records, while Oracle uses ROWNUM.
Syntax:
SELECT column_name(s)
FROM table_name
WHERE condition
LIMIT number;
E.g.:
From your screenshot, subscription id is same for multiple id's you want to get last record which id is greater. The below query gets your result, grouped by subscription_id and ordered by id desc and limiting to 1 makes fetching only 1 row from database.
select * from tableName group by subscription_id order by id desc limit 1
You can used last() function.
SELECT LAST(CustomerName) AS LastCustomer FROM Customers;
I have a sql statement is with pattern
SELECT id FROM table WHERE [conditions] ORDER BY [orders] LIMIT 10000 OFFSET 0
and the return value is like below:
id
-----
1
0
0
0
0
1
1
1
2
2
...
Then I want to get the distinct value as the order of their first appearance, since there's an ORDER BY in the sql, and DISTINCT or GROUP BY are both happened before ORDER BY in a sql, I tried below sql.
SELECT DISTINCT id FROM (SELECT id FROM table WHERE [conditions] ORDER BY [orders] LIMIT 10000 OFFSET 0) tmp;
And the result is like what I want:
id
----
1
0
2
...
My question is: can I ensure that in a same pattern SQL, DISTINCT will always return the distinct id as the order their first appearance?
Thanks.
---------------Notes------------------
Below can be ignored. I just noticed many peoples are recommended to try GROUP BY, so I tried below sql as well:
SELECT id FROM (SELECT id FROM table WHERE [conditions] ORDER BY [orders] LIMIT 10000 OFFSET 0) tmp GROUP BY id;
but the returning is reordered by the alpha-beta order (it's not integer order because the column is a CHAR column for the real id is a string), which is not what I want.
id
----
0
1
10
100
....
If you want results in a particular order, then you need to specify that in the ORDER BY for the outermost SELECT. That suggests something like this:
SELECT id
FROM tabl
WHERE [conditions]
ORDER BY [orders]
LIMIT 10000 OFFSET 0
Then, if you want to order by the first appearance, you need a column that specifies the first appearance. Let's call this CreatedAt (perhaps it is orders?). If so:
SELECT id
FROM table
WHERE conditions
GROUP BY id
ORDER BY min(CreatedAt)
LIMIT 10000;
Note: SQL tables represent unordered sets, so you need a column to specify the ordering of interest.
I have table that looks like this:
id rank
a 2
a 1
b 4
b 3
c 7
d 1
d 1
e 9
I need to get all the distinct rank values on one column and count of all the unique id's that have reached equal or higher rank than in the first column.
So the result I need would be something like this:
rank count
1 5
2 4
3 3
4 3
7 2
9 1
I've been able to make a table with all the unique id's with their max rank:
SELECT
MAX(rank) AS 'TopRank',
id
FROM myTable
GROUP BY id
I'm also able to get all the distinct rank values and count how many id's have reached exactly that rank:
SELECT
DISTINCT TopRank AS 'rank',
COUNT(id) AS 'count of id'
FROM
(SELECT
MAX(rank) AS 'TopRank',
id
FROM myTable
GROUP BY id) tableDerp
GROUP BY TopRank
ORDER BY TopRank ASC
But I don't know how to get count of id's where the rank is equal OR HIGHER than the rank in column 1. Trying SUM(CASE WHEN TopRank > TopRank THEN 1 END) naturally gives me nothing. So how can I get the count of id's where the TopRank is higher or equal to each distinct rank value? Or am I looking in the wrong way and should try something like running totals instead? I tried to look for similar questions but I think I'm completely on a wrong trail here since I couldn't find any and this seems a pretty simple problem that I'm just overthinking somehow. Any help much appreciated.
One approach is to use a correlated subquery. Just get the list of ranks and then use a correlated subquery to get the count you are looking for:
SELECT r.rank,
(SELECT COUNT(DISTINCT t2.id)
FROM myTable t2
WHERE t2.rank >= r.rank
) as cnt
FROM (SELECT DISTINCT rank FROM myTable) r;
I have a table user_comission_configuration_history and I need to select the last Comissions configuration from a user_id.
Tuples:
I'm trying with many queries, but, the results are wrong. My last SQL:
SELECT *
FROM(
SELECT * FROM user_comission_configuration_history
ORDER BY on_date DESC
) AS ordered_history
WHERE user_id = 408002
GROUP BY comission_id
The result of above query is:
But, the correct result is:
id user_id comission_id value type on_date
24 408002 12 0,01 PERCENTUAL 2014-07-23 10:45:42
23 408002 4 0,03 CURRENCY 2014-07-23 10:45:41
21 408002 6 0,015 PERCENTUAL 2014-07-23 10:45:18
What is wrong in my SQL?
This is your query:
SELECT *
FROM (SELECT *
FROM user_comission_configuration_history
ORDER BY on_date DESC
) AS ordered_history
WHERE user_id = 408002
GROUP BY comission_id;
One major problem with your query is that it uses a MySQL extension to group by that MySQL explicitly warns against. The extension is the use of other columns in the in theselect that are not in the group by or in aggregation functions. The warning (here) is:
MySQL extends the use of GROUP BY so that the select list can refer to
nonaggregated columns not named in the GROUP BY clause. This means
that the preceding query is legal in MySQL. You can use this feature
to get better performance by avoiding unnecessary column sorting and
grouping. However, this is useful primarily when all values in each
nonaggregated column not named in the GROUP BY are the same for each
group. The server is free to choose any value from each group, so
unless they are the same, the values chosen are indeterminate.
So, the values returned in the columns are indeterminate.
Here is a pretty efficient way to get what you want (with "comission" spelled correctly in English):
SELECT *
FROM user_commission_configuration_history cch
WHERE NOT EXISTS (select 1
from user_commission_configuration_history cch2
where cch2.user_id = cch.user_id and
cch2.commission_id = cch.commission_id and
cch2.on_date > cch.on_date
) AND
cch.user_id = 408002;
Here's one way to do what your trying. It gets the max date for each user_ID and commissionID and then joins this back to the base table to limit the results to just the max date for each commissionID.
SELECT *
FROM user_comission_configuration_history A
INNER JOIN (
SELECT User_ID, Comission_Id, max(on_Date) mOn_Date
FROM user_comission_configuration_history
Group by User-Id, Comission_Id
) B
on B.User_ID = A.User_Id
and B.Comission_Id = A.Comission_ID
and B.mOnDate=A.on_date
WHERE user_id = 408002
ORDER BY on_Date desc;