SQL Ordering rows in a select with multiple conditions - mysql

I am trying to create an SQL Query to select rows from a database, ordered by a numerical field, however there are repeated entries in the table.
The table consists of the following columns.
UID - Numerical Unique ID
ACCOUNT_NAME - Account Name, unchanged
NICK_NAME - Can be changed by the user at any time
POINTS - Records points held by the user's account
The goal of the query is to display the Account_Name ordered by Points. However, Account_Name is not unique and can appear multiple times in the table.
To deal with this I would like to display only the latest row for each Account_Name.
This meaning that in the results from the select each Account_Name should only appear once. I am trying to have the selection be decided by the UID, meaning that I want only the row with the greatest UID where each account_name appears to be displayed.
I have tried the following without desired results. (The name of the table is ACCOUNT)
SELECT DISTINCT A.account_name , A.uid, A.points
FROM account A, account B
where A.account_name = B.account_name
and A.points > 0
and A.uid >= B.uid
order by A.points DESC;
This doesn't give me the desired results, specifically, there is an account in the database where an outdated row exists with a high value in the Points column. This record appears as the first result in the select, even though it is outdated.
How would you recommend adjusting this Query to select the desired information?
I hope this is enough information to work off of (first time posting a question) Thank you for you help :)
EDIT: Adding in examples with data.
Sample Table Data:
Sample Table Data
Current Results:
Current Results
Desired Results:
Desired Results

Consider joining on an aggregate query calculating MAX(UID)
SELECT a.account_name, a.uid, a.points
FROM account a
INNER JOIN
(
SELECT account_name, MAX(uid) AS max_uid
FROM account
GROUP BY account_name
) agg
ON a.account_name = agg.account_name
AND a.uid = agg.max_uid)
WHERE a.points > 0
ORDER by a.points DESC;
Alternatively, with MySQL 8.0, consider a window function:
SELECT a.account_name, a.uid, a.points
FROM account a
WHERE a.points > 0
AND a.uid = MAX(a.uid) OVER (PARTITION BY a.account_name)
ORDER by a.points DESC;

Related

MySQL Values Relying on Different Tables

In this database:
I need to write an SQL query that will display the name of each client of the agent with the highest agent rating in the company.
What I'm trying right now is,
SELECT ClientName
FROM CLIENT.ClientName
WHERE CLIENT.AgentID = AGENT.AgentID AND MAX(AGENT.AgentRating);
I'm new to MySQL, so I just want to check if I'm using the MAX and AND operators properly, or if there's a simpler way to do this.
Try using a subquery to select the highest rated agent, then join it to your CLIENT table to select the names of the associated clients. Something like this:
SELECT ClientName
FROM CLIENT.ClientName
JOIN (
SELECT AgentID FROM AGENT ORDER BY AgentRating DESC LIMIT 1
) sq ON sq.AgentID = CLIENT.AgentID
The subquery (SELECT AgentID FROM AGENT ORDER BY AgentRating DESC LIMIT 1) sq selects the AgentID column from the AGENT table
Then with ORDER BY AgentRating DESC it orders that column by the AgentRating descending placing the highest rating at the top of the results.
Then the LIMIT 1 limits the rows returned to 1, giving you only 1 (the first returned) record from the AGENT table that we just ordered to put the highest rated agent at the top.
Then when you JOIN that result from the subquery with your CLIENT table on the AgentID, you will only get results in your CLIENT table maching the selected AgentID from the subquery.

MySQL joining 2 tables Wrong output..the value multiply

I have a major problem for my Capstone project. I'm joining 2 tables from my database but the output is
MY Query: select Distinct tbl_attendance_in.time_in as time_in,tbl_attendance_out.time_in as time_out from tbl_attendance_in join tbl_attendance_out on tbl_attendance_in.user_id=tbl_attendance_out.user_id where tbl_attendance_in.user_id=4 AND tbl_attendance_out.user_id=4;
I've already tried all sorts of joining like inner right,outer right,inner join but still no luck.
Maybe you can make a sub-query for both of the tables first and generate a row number based on the time_in column ordering. Then you do a LEFT JOIN between those two. Something like this example query below:
SELECT A.user_id,A.time_in,B.time_in AS 'time_out' FROM
/*the first sub-query is for time in table*/
(SELECT user_id, time_in,ROW_NUMBER() OVER (ORDER BY time_in) AS RowN
FROM tbl_attendance_in WHERE user_id=4) A
LEFT JOIN
/*the second sub-query is for time out table*/
(SELECT user_id, time_in,ROW_NUMBER() OVER (ORDER BY time_in) AS RowN
FROM tbl_attendance_out WHERE user_id=4) B
ON A.User_id=B.User_id AND A.RowN=B.RowN;
I'm using ROW_NUMBER() OVER () function to generate a running number for each of the row data then using it in the ON for the LEFT JOIN. Although this can give you the result for your current example, it might not be the best solution considering other factors like date of the time_in and time_out must match, or if there's any duplicate (but valid) timestamp in one of the table.
Another that you can consider is using UNION ALL. Example below:
SELECT 'IN' AS Opr, user_id, time_in AS records,ROW_NUMBER() OVER (ORDER BY time_in) AS RowN
FROM tbl_attendance_in WHERE user_id=4 UNION ALL
SELECT 'OUT' AS Opr, user_id, time_in AS records,ROW_NUMBER() OVER (ORDER BY time_in) AS RowN
FROM tbl_attendance_out WHERE user_id=4 order by RowN, records;
This also uses ROW_NUMBER() function for the ordering and I added Opr column to indicate which operation (or table) its coming from.
Maybe you can try both and see if you can use it. If you have other concern, just edit your question and add more details.
To fiddle around: https://dbfiddle.uk/?rdbms=mariadb_10.3&fiddle=087e4a7cabb5e50090639b5f3435aaa7
If it multiplies the data then you can use group by at the end of your query.
select Distinct tbl_attendance_in.time_in as time_in,tbl_attendance_out.time_in as time_out from tbl_attendance_in join tbl_attendance_out on tbl_attendance_in.user_id=tbl_attendance_out.user_id where tbl_attendance_in.user_id=4 AND tbl_attendance_out.user_id=4 group by tbl_attendance_in.time_in,tbl_attendance_out.time_in ;
this will group the duplicate rows.

MySQL Group two column with where clause on both two group

What I have:
I have two table , first is user_faktorha save invoices data and second is u_payment save payment data .
What I want:
I want to group all data from this two table and have a result as one table with sum both table.
My two table with sample query's is on sqlfiddle : http://sqlfiddle.com/#!2/b9f9e/4
What's problem:
I try to solve this problem , but give wrong result each time , for example (can be see on sqlfiddle) , user/tell named as habib on give wrong sum(price) result.
habib's faktorhaprice = -508261 and habib's paymentprice = 648000 but sum result in main query have wrong data -7115654 and 13000000
what's the solution ?
(Updated) One way:
SELECT tell,SUM(FAKTORHAPRICE) FAKTORHAPRICE, SUM(PaymentPrice) PaymentPrice
FROM (SELECT tell, price as FAKTORHAPRICE, null PaymentPrice
from user_faktorha
union all
SELECT Username as tell, null as FAKTORHAPRICE, Price as PaymentPrice
FROM `u_payment` WHERE Active='1') sq
GROUP BY tell ORDER BY FAKTORHAPRICE ASC;
SQLFiddle here.
The essence of your problem here is that you are trying to relate to unrelated tables. Sure they have common data in the user name, but there is not a clean relation between them like an invoice id that can be used to relate the items together such that the OUTER JOIN wouldn't duplicate records in your result set. My suggestion would be to do the aggregation on each table individually and then join the results like this:
SELECT f.tell, f.faktorhaprice, p.paymentprice
FROM
(SELECT tell, SUM(price) AS faktorhaprice FROM user_faktorha GROUP BY tell) AS f
INNER JOIN
(SELECT username, SUM(price) AS paymentprice FROM u_payment GROUP BY username) AS p
ON f.tell = p.username

I want to use max and count aggregate functions together in mysql query

I am using mysql 5.0.51b.
I have one table named xyz.
xyz table has a columns abc,location,pqr and lmn
Everytime an information is sent to particular location, its entry is done in xyz table.
I want to have the name of the location to which maximum information is sent.
The way i tried:
First of all i count the number of entries sent to each location using count and group by.
Now, the problem is to have the name(s) of the location with maximum values.
I have used temporary solution:
I use order by clause and limit to get the first record that has max values.
But this has one problem
If two locations has same count then above solution will give only one location and the other with same count will not be returned.
I want to solve this problem
Any hint will be very helpful
Thanks in anticipation
Thank you very much to everyone who has responded to my question and spared time to solve my problem.
However, i have got the solution:
SELECT count( * ) AS cnt2, location
FROM sms
GROUP BY location
HAVING cnt2 = (
SELECT count( * ) AS cnt
FROM sms
GROUP BY location
ORDER BY cnt DESC
LIMIT 1 );
very important hint on http://lists.mysql.com/mysql/203074
The inner query gives you the max count and outer query compares each count with max count.
Select MAX(cnt.Total) from
(select count( Name)as Total from Gk_RegUser_answer_rel group by Reg_UserId) As cnt
Try this interesting solution -
SELECT x.* FROM xyz x
JOIN (
SELECT GROUP_CONCAT(location) locations FROM (
SELECT location, COUNT(*) cnt FROM xyz GROUP BY location ORDER BY COUNT(*)) t
GROUP BY cnt DESC
LIMIT 1
) t
ON FIND_IN_SET(x.location, t.locations);
SELECT COUNT(*), `location` FROM `xyz` GROUP BY `location`
Above query will give you the information count to a specific location.
If this is not what you were looking for, can you provide some sample data and expected output?

Mysql Groupby and Orderby problem

Here is my data structure
alt text http://luvboy.co.cc/images/db.JPG
when i try this sql
select rec_id, customer_id, dc_number, balance
from payments
where customer_id='IHS050018'
group by dc_number
order by rec_id desc;
something is wrong somewhere, idk
I need
rec_id customer_id dc_number balance
2 IHS050018 DC3 -1
3 IHS050018 52 600
I want the recent balance of the customer with respective to dc_number ?
Thanx
There are essentially two ways to get this
select p.rec_id, p.customer_id, p.dc_number, p.balance
from payments p
where p.rec_id IN (
select s.rec_id
from payments s
where s.customer_id='IHS050018' and s.dc_number = p.dc_number
order by s.rec_id desc
limit 1);
Also if you want to get the last balance for each customer you might do
select p.rec_id, p.customer_id, p.dc_number, p.balance
from payments p
where p.rec_id IN (
select s.rec_id
from payments s
where s.customer_id=p.customer_id and s.dc_number = p.dc_number
order by s.rec_id desc
limit 1);
What I consider essentially another way is utilizing the fact that select rec_id with order by desc and limit 1 is equivalent to select max(rec_id) with appropriate group by, in full:
select p.rec_id, p.customer_id, p.dc_number, p.balance
from payments p
where p.rec_id IN (
select max(s.rec_id)
from payments s
group by s.customer_id, s.dc_number
);
This should be faster (if you want the last balance for every customer), since max is normally less expensive then sort (with indexes it might be the same).
Also when written like this the subquery is not correlated (it need not be run for every row of the outer query) which means it will be run only once and the whole query can be rewritten as a join.
Also notice that it might be beneficial to write it as correlated query (by adding where s.customer_id = p.customer_id and s.dc_number = p.dc_number in inner query) depending on the selectivity of the outer query.
This might improve performance, if you look for the last balance of only one or few rows.
I don't think there is a good way to do this in SQL without having window functions (like those in Postgres 8.4). You probably have to iterate over the dataset in your code and get the recent balances that way.
ORDER comes before GROUP:
select rec_id, customer_id, dc_number, balance
from payments
where customer_id='IHS050018'
order by rec_id desc
group by dc_number