Mysql Query problem? - mysql

ID NAME AMT
1 Name1 1000
2 Name2 500
3 Name3 3000
4 Name1 5000
5 Name2 2000
6 Name1 3000
consider above table as sample.
am having a problem in my sql query, Am using like this.
Select name,amt from sample where amt between 1000 and 5000
it returns all the values in the table between 1000 and 5000, instead I want to get maximum amount record for each name
i.e.,
3 name3 3000
4 name1 5000
5 name2 2000

select name, max(amt) from sample group by name
You'll have problems getting the id, though, as there may be more than one.

you should group by NAME:
SELECT `name`,MAX(amt) from sample GROUP BY `name` where amt between 1000 and 5000

If you only need ONE of the ids that contains the MAX(amt), then this will do the trick:
SELECT id, name, MAX(amt)
FROM sample
WHERE amt BETWEEN 1000 AND 5000
GROUP BY name;
If you need all the ids, then it gets more complicated. Two queries are required, plus a temporary table:
CREATE TEMPORARY TABLE maxamts
SELECT name AS maxname, MAX(amt) AS maxamt
FROM sample
WHERE amt BETWEEN 1000 AND 5000
GROUP BY maxname;
SELECT GROUP_CONCAT(id), maxname AS name, maxamt AS amt
FROM maxamts
LEFT JOIN sample ON ((maxname = sample.name) AND (maxamt = amt))
GROUP BY maxname;
In short: Create a temporary table from the query that finds each name/max(amt) pair, then use that temporary table to join back on the original table and pull out the IDs matching the name/amount combinations.
Just remember that group_concat is by default limited to 1,024 characters, (show variables like '%group_concat%' to see the max length on your server), so if you've got a large dataset, increase that limit, or remove the group_concat and group by from the second query and parse the information in your application.

select id, name, amt from sample where amt = (select max(amt) from sample)
that should return all records that have the max amt from the sample table
edit:
select id, name, amt
from sample
where amt = (
select max(amt)
from sample
where amt between 1000 and 5000)
this query will return all records that have an amount equal to the max amount between 1000 and 5000

Related

SQL Query Sequential Month Logins

I have the following SQL table
username
Month
292
10
123
12
123
1
123
2
123
4
345
6
345
7
I want to query it, to get each username's login streak in Count of sequential Month. meaning the end result I am looking for looks like this :
username
Streak
292
1
123
3
345
2
How can I achieve it ? taking into note the Month 12 --> Month 1 issue;
Appreciate your help;
This would give you the result you want:
select username, count(*)
from (
select
username
, month_1
, coalesce(nullif(lead(month_1)
over (partition by username
order by coalesce(nullif(month_1,12),0))
- coalesce(nullif(month_1,12),0),-1),1) as MonthsTillNext
from login_tab
) Step1
where MonthsTillNext=1
group by username
By calculating the difference from the next row, where the next row is defined as the next month_no in ascending order, treating 12 as 0 (refer to the ambiguity I mentioned in my comment). It then just leaves the rows for consecutive months rows, and counts them.
Beware though, in addition to the anomaly around month:12, there is another case not considered: if the months for the user are 1,2,3 and 6,7,8 this would count as Streak:6; is it what you wanted?
One way would be with a recursive CTE, like
WITH RECURSIVE cte (username, month, cnt) AS
(
SELECT username, month, 1
FROM test
UNION ALL
SELECT test.username, test.month, cte.cnt+1
FROM cte INNER JOIN test
ON cte.username = test.username AND CASE WHEN cte.month = 12 THEN 1 ELSE cte.month + 1 END = test.month
)
SELECT username, MAX(cnt)
FROM cte
GROUP BY username
ORDER BY username
The idea is that the CTE (named cte in my example) recursively joins back to the table on a condition where the user is the same and the month is the next one. So for user 345, you have:
Username
Month
Cnt
345
6
1
345
7
1
345
7
2
The rows with cnt=1 are from the original table (with the extra cnt column hardcoded to 1), the row with cnt=2 is from the recursive part of the query (which found a match and used cnt+1 for its cnt). The query then selects the maximum for each user.
The join uses a CASE statement to handle 12 being followed by 1.
You can see it working with your sample data in this fiddle.
The one shared by #EdmCoff is quite elegant.
Another one without recursive and just using conditional logic -
with data_cte as
(
select username, month_1,
case when (count(month_1) over (partition by username) = 1) then 1
when (lead(month_1) over (partition by username order by username) - month_1) = 1 OR (month_1 - lag(month_1) over (partition by username order by username)) = 1 then 1
when (month_1 = 12 and min (month_1) over (partition by username) =1) then 1
end cnt
from login_tab
)
select username, count(cnt) from data_cte group by username
DB Fiddle here.

How do I find the average of the result of a group by SQL query?

So assuming I'm starting with a table called Inventory like the following where there are multiple unique items per non unique storage ID:
ItemID
StorageID
453
100
234
100
642
150
234
200
343
200
143
200
I group the items based on its storage ID so it would result in the following table - (select itemID, storageID from Inventory group by storageID)
ItemID
StorageID
453, 234
100
642
150
234, 343, 143
200
But then here is the part I'm stuck on: I want to return a single numerical result representing the average number of items per storage. So that would involve counting the number of items per each distinct storage (ie: storageID 100 has 2 items, storageID 200 has 3 items) and then finding an average. So in the example I shared, the average would be (2+1+3)/3 = 2.67 items/storage.
How could I query MySQL for this? Do I even need to use group by as a start?
Group your data and use count() on each group.
select avg(cnt)
from
(
select count(*) as cnt, storageID
from Inventory
group by storageID
) tmp
You can use group by as follows:
select avg(cnt) as average_
(select count(*) as cnt
from your_table t
group by storageid) t
You don't need a subquery:
select count(*) / count(distinct storageID) as avg_per_storageID
from Inventory ;
The average is the total number of items divided by the number of storageIDs.

How do I get the top 4 results of a column in mysql query?

I'm not very experienced in mySQL, but
I have a SQL query table where I need to return:
Salary_amount_1
Salary_amount_2
Salary_amount_3
Salary_amount_4
(not relevant below)
Salary_Date_1
Salary_Date_2
Salary_Date_3
Salary_Date_4
I've got 4 seperate columns for each salary amount to select into in the destination table we're inserting into, and a column called Salary with 15+ different amounts in the source table we're selecting from, but how do I specifically select the first salary for column 1, second for column two, third for three and fourth salary for column four?
Thanks in advance
What I have tried:
This is what I have (and isn't working for me yet)
Select
ID,
Bank Name,
UserName,
min(details_Credit) as Salary_Amount_1,
max(details_Credit) as Salary_Amount_2,
Case
when details_Credit = min(details_Credit)
and details_Credit > min(details_Credit)
end Salary_Amount_3,
????? as Salary_Amount_4,
any help would be appreciated. thank you
Sample Data:
Salary| SalaryDate| UserName| BankName
=====================================
1000 |2013-05-23 |MikeRoss |NetBank
1500 |2013-06-23 |MikeRoss |NetBank
2000 |2013-07-22 |MikeRoss |NetBank
1000 |2013-08-15 |MikeRoss |NetBank
Desired Results:
Username|Bank|Salary1|Salary2|Salary3|Salary4|Date1|Date2|Date3|Date4
MikeRoss|Netbank|1000|1500|2000|1000|2013-05-23| 2013-06-23| 2013-06-22| 2013-08-15
I think what you need is something like this:
Select ID, Bank Name, UserName, Salary_amount_1 from yourTable
order by Salary_amount_1 limit 1
Union
Select ID, Bank Name, UserName, Salary_amount_2 from yourTable
order by Salary_amount_2 limit 1,1
Union
Select ID, Bank Name, UserName, Salary_amount_3 from yourTable
order by Salary_amount_3 limit 2,1
Union
Select ID, Bank Name, UserName, Salary_amount_4 from yourTable
order by Salary_amount_4 limit 3,1
This will perform 4 queries, each returning one of your desired results.
limit offset, rowcount will take the first rowcount rows after skipping offset rows.
That said, I strongly advice you to check the structure of your table.
I used Left Join instead to resolve this incase anyone is wondering. i.e
left join DB.Table_Name as a1 on a1.ID=a.ID and a1.TransactionDate=a0.maxDate
left join DB.Table_Name as a2 on a2.ID=a1.ID and a2.TransactionDate<a1.TransactionDate
left join DB.Table_Name as a3 on a3.ID=a2.ID and a3.TransactionDate<a2.TransactionDate
etc

MySQL group multiple rows based on DISTINCT value

I need to display the last 2 results from a table (results), the results are comprised of several rows with matching submissionId, The number of rows per submission is unknown, and of course I prefer a single query.
Here is the DB table structure
submissionId input value
1 name jay
1 phone 123-4567
1 email test#gmail.com
2 name mo
2 age 32
3 name abe
3 email abe#gmail.com
4 name jack
4 phone 123-4567
4 email jack#gmail.com
Desierd results:
submissionId input value
3 name abe
3 email abe#gmail.com
4 name jack
4 phone 123-4567
4 email jack#gmail.com
Or even better, if I can combine the rows like this:
3 name abe 3 email abe#gmail.com
4 name jack 4 phone 123-4567 4 email jack#gmail.com
One option here is to use a subquery to identify the most recent and next to most recent submissionId:
SELECT submissionId, input, value
FROM yourTable
WHERE submissionId >= (SELECT MAX(submissionId) FROM yourTable) - 1
ORDER BY submissionId
Demo here:
SQLFiddle
Update:
If your submissionId column were really a date type, and you wanted the most recent two dates in your result set, then the following query will achieve that. Note that the subquery in the WHERE clause, while ugly, is not correlated to the outer query. This means that the MySQL optimizer should be able to figure out that it only needs to run it once.
SELECT submissionDate, input, value
FROM yourTable
WHERE submissionDate >=
(SELECT MAX(CASE WHEN submissionDate = (SELECT MAX(submissionDate) FROM yourTable)
THEN '1000-01-01'
ELSE submissionDate
END) FROM yourTable)
ORDER BY submissionDate
SQLFiddle
You can use limit in subqueries in the from clause, so a typical way to write this is:
SELECT submissionDate, input, value
FROM t join
(select distinct submissionDate
from t
order by submissionDate desc
limit 2
) sd
on t.submissionDate = sd.submissionDate;
This is how the query looks like now, so i can get the results with a LIMIT, RANGE, and id/timestamp (with help of Tim and Gordon):
SELECT *
FROM rmyTable t
JOIN
(SELECT DISTINCT sd.submissionId
FROM myTable sd
WHERE sd.questionId = yourId
ORDER BY sd.submissionId
LIMIT 2
) t2
ON t.submissionId = t2.submissionId
WHERE t.formId = yourId
AND dateTime BETWEEN 0000 AND 1111

Can't Sum a New Data In MySQL After Inner Join

Got some problem after using inner join, this is my query
> insert into total(ID,Grade) select midsemester.ID,(midsemester.grade +
> endsemester.grade) as total from midsemester inner join endsemester on
> midsemester.ID = endsemester.ID
This is the table:
Table name: midsemester
ID Grade
1 10
2 30
3 40
Table name: endsemester
ID Grade
1 30
2 40
3 20
and i need to sum these table to new table called total. This is the results that i was hoping.
Table name: total
ID Grade
1 40
2 70
3 60
I actually just need to sums up the grade's value using the id for the 3rd table. And tried several times using inner join, it's working. But when I try to insert a new data, the table of total can't sum a new data. Would appreciate any help, thanks! :)
I think you wang union all with an aggregation:
insert into total(ID,Grade)
select ID, sum(grade) as total
from (select id, grade from midsemester union all
select id grade from endsemester
) me
group by id;
However, this is a bad structure for the grades. You should store them all in one table, with a column indicating whether the grade is "midsemester" or "endsemester".