Why adding SUM changes the number of retrieved rows? - mysql

I have this sql which gives me 6 rows without SUM clause (sur can give more if condition is true)
SELECT id, prodname, prodid, st_date, montant, tvaval, quantite, status, factureno
FROM StockData WHERE " + VenteWhere + " ORDER BY " + Order_by + " " + SortDir + "
PS: VenteWhere, Order_by abd SortDir are the variables.
BUt when I add SUM(quantite) I get only one row. Is there a way to have 6 rows data and the sum of 6 rows or I have to do another query for getting it

I think you can use
SELECT id, prodname, prodid, st_date, montant, tvaval, SUM(quantite), status, factureno
FROM StockData
WHERE " + VenteWhere + "
ORDER BY " + Order_by + " " + SortDir + "
GROUP BY xxxxx
Where xxxxx represents the variable you want to group by per row.
Summing will remove the rows its sums over and only display the sum itself. So you have to group by some variable to make it split the results over that variables 'occurence'

Related

Mysql Query With Like Operator and order by keyword giving empty records in spring boot api

native Query I Wrote in My Repository
If i remove order by condition in the below query , it is giving some records but i want it in some order so i added order by condition then it not showing records only . but the same mysql query with order by condition is giving some records in mysql workbench.
#Query(value = "SELECT l.id AS id,l.first_name AS firstName,l.last_name AS lastName,"
+ " l.email AS email,l.phone AS phone,l.place AS place,l.course_id AS courseId,"
+ " c.name AS courseName,l.source AS source,l.enquiry_for AS enquiryFor,"
+ " l.appointment_date AS appointmentDate,l.description AS description,"
+ " l.discount AS discount,l.status AS status,l.assignee_id AS assigneeId,"
+ " ase.first_name AS assigneeFirstName,ase.last_name AS assigneeLastName,"
+ " l.assignor_id AS assignorId,asr.first_name AS assignorFirstName,"
+ " asr.last_name AS assignorLastName,l.active AS active,l.created_date AS createdDate,"
+ " l.updated_date AS updatedDate,(SELECT comments FROM reviews where created_date IN"
+ " (SELECT MAX(created_date) from reviews where lead_id=l.id)) AS latestComment FROM "
+ " leads l JOIN users AS ase ON l.assignee_id = ase.id JOIN users AS asr ON "
+ " l.assignor_id = asr.id JOIN courses AS c ON l.course_id =c.id WHERE l.status!='Draft'"
+ " AND (l.first_name LIKE '%:keyword%' OR l.last_name LIKE '%:keyword%' OR l.phone LIKE"
+ " '%:keyword%') ORDER BY -l.appointment_date DESC,l.created_date ASC", nativeQuery=true)
List<Leads> searchLeadsForAdmin(#Param("keyword") String searchKeyword);
i don't know Where am i going wrong , attached image below mysql query result came in workbench.
I found the answer to my question. It was a concatenation issue. In the second last line of my query after 'l.phone LIKE' I added the value in the next line.
+ " AND l.first_name LIKE %:keyword% OR l.last_name LIKE %:keyword% OR "
+ " l.phone LIKE %:keyword% ORDER BY -l.appointment_date DESC,"
+ " l.created_date ASC", nativeQuery = true)
The above query works.

How to re-use result from a SELECT statement?

My goal is to re-use the result from a SELECT statement to be used in SQL EXISTS statement.
The general idea looks like this:
SELECT *
FROM table
WHERE col1=1
OR EXISTS (
SELECT 1 // this is an exact copy of the SELECT statement above.
FROM table
WHERE col=1
)
The actual SQL statement I am trying to reduce:
"SELECT user_detail.user, user_detail.name, channel_member.role " +
"FROM user_detail " +
"JOIN channel_member ON user_detail.user=channel_member.user " +
"AND channel_member.uuid=#{channelUuid} " +
"WHERE user_detail.user=#{username} " +
"OR EXISTS ( " +
" SELECT 1" +
" FROM user_detail " +
" JOIN channel_member ON user_detail.user=channel_member.user " +
" AND channel_member.uuid=#{channelUuid} " +
" WHERE user_detail.user=#{username} " +
")"
You can only do this if your version of MySQL supports window functions, ie. version >= 8.0
You can use conditional window aggregation, like this:
SELECT *
FROM (
SELECT *, COUNT(CASE WHEN col1 = 1 THEN 1 END) OVER () AS CountMatches
FROM table
) t
WHERE CountMatches > 0;
Depending on the number of rows matching to non-matching, this may be more or less performant. You need to test.
This query:
SELECT *
FROM table
WHERE col1 = 1 OR
EXISTS (SELECT 1 // this is an exact copy of the SELECT statement above.
FROM table
WHERE col=1
)
Doesn't really make sense. It is saying to return all rows if col = 1 is in the table -- but then it filters to check if any row has col = 1. So it is equivalent to:
SELECT *
FROM table
WHERE (SELECT 1 FROM table t2 WHERE t2.col = 1);
I strongly suspect that you intend NOT EXISTS -- so get everything with 1. If there is no 1 then return everything:
SELECT *
FROM table
WHERE col1 = 1 OR
NOT EXISTS (SELECT 1 // this is an exact copy of the SELECT statement above.
FROM table
WHERE col = 1
);
This should work fine with tables -- and is in fact probably optimal with the right indexes.
If "table" is really a complex query, then you might consider window functions:
select t.*
from (select t.*,
sum( col = 1 ) as num_1s
from t
) t
where col = 1 or num_1s = 0;
If you want to use any conditional statement on the query you are running you will need to wrap the query and put it in a FROM statement and then run the conditional outside of the query, like so....
SELECT aliasName.*
FROM
(SELECT *
FROM table
WHERE col1=1) aliasName
WHERE EXISTS aliasName //this is the conditionl statement OUTSIDE of the query you built.
Let me know how you do...
For Mr./Ms. Barmar:
The idea
// Idea:
// If one of the row have col1 with value 1.
// Then return all of the row, or return empty []
// SELECT *
// FROM table
// WHERE col1=1
// OR EXISTS (
// SELECT 1
// FROM table
// WHERE col=1
// )
The solution
"WITH temp AS (" +
" SELECT user_detail.user, user_detail.name, channel_member.role " +
" FROM user_detail " +
" JOIN channel_member ON user_detail.user=channel_member.user " +
" AND channel_member.uuid=#{channelUuid} " +
") " +
"SELECT * " +
"FROM temp " +
"WHERE user=#{username} " +
" OR EXISTS ( " +
" SELECT 1" +
" FROM temp " +
" WHERE user=#{username} " +
" )"
The solution above use WITH clause as recommended by Mr./Ms. Barmar, I am posting this, so you can inspect whether this is logical or not.

MySQL: How to optimize result of SUM of fields?

I have this query:
SELECT name, SUM(count_1 + count_2 + count_3 + count_4 + count_5 + count_6) AS Total
FROM my_table
Is there a way to add these values count_1 + count_2 + count_3 + count_4 + count_5 + count_6 and so on.. more efficiently? MySQL keeps crashing for me when I add huge numbers of fields.
Regardless of whether the db design is right or wrong if you use an aggregation function you should use group by
SELECT name, SUM(count_1 + count_2 + count_3 + count_4 + count_5 + count_6) AS Total
FROM my_table
GROUP BY name

[21000][1242] Subquery returns more than 1 row

My Query:
entityManager.createQuery("SELECT " +
"q.id, " +
"q.title, " +
"q.user.fullName, " +
"q.user.reputationCount, " +
"q.viewCount, " +
"q.countValuable, " +
"q.persistDateTime, " +
"t.id, " +
"t.name, " +
"t.description, " +
"(SELECT COUNT (a) FROM Answer a WHERE a.question.id = q.id), " +
"(SELECT a.isHelpful FROM Answer a WHERE a.question.id = q.id) " +
"FROM Question q JOIN q.tags t")
Here I get the error - [21000][1242] Subquery returns more than 1 row
By the method of exceptions, I determined that the error in this query string:
"(SELECT a.isHelpful FROM Answer a WHERE a.question.id = q.id) "
How to make the correct request so that there is no this error? Thank!
Two common ways are aggregation and limiting:
(SELECT MAX(a.isHelpful) FROM Answer a WHERE a.question.id = q.id)
(SELECT a.isHelpful FROM Answer a WHERE a.question.id = q.id LIMIT 1)
However, those are really just hacks to get around an "issue" with the data. I put issue in quotes, but the real issue is probably your understanding of data and not the data itself.
You should understand why there are duplicates. Then decide which value you want. And implement the correct logic for what you want.
Subquery returns more than 1 row, this simply means that your query is not returning a single row for the outer select statement to work.
"(SELECT a.isHelpful FROM Answer a WHERE a.question.id = q.id) "
you have to apply a set of conditions to filter out your data uniquely or use joins to combine your table Answer and Question and then filter data accordingly.
you can also group each row data in one column by GROUP_CONCAT Mysql function like this :
"(SELECT GROUP_CONCAT(a.isHelpful) FROM Answer a WHERE a.question.id = q.id) "
Although GROUP_CONCAT is not available in Mysql, for that you can also bind SQL function in hibernate as described in this post.
After a day of various trial and error, I found the following solution, I hope someone will broaden their horizons and help in solving their problem:
entityManager.createQuery("SELECT " +
"q.id, " +
"q.title, " +
"q.user.fullName, " +
"q.user.reputationCount, " +
"q.viewCount, " +
"q.countValuable, " +
"q.persistDateTime, " +
"t.id, " +
"t.name, " +
"t.description, " +
"(SELECT COUNT (a) FROM Answer a WHERE a.question.id = q.id), " +
"(SELECT CASE WHEN MAX (a.isHelpful) > 0 THEN true ELSE false END FROM Answer a WHERE a.question.id = q.id) " +
"FROM Question q JOIN q.tags t")

I need help finding the average number out of 60 columns, where the columns number does not equal 0

We have 2500 products on our site, ranked between 60 different categories. Our DB scheme is 61 columns, labled "product_id", and then the categories: "category_1", "category_2"... "category_60", and 2500 rows, one for each product. If a product is not ranked in a specific cateogry, that corresponding field is marked "0". If it is ranked, the field is an INT with whatever rank it is: "1" is 1st, "2" is second, etc.
Usually products are only ranked in 2-3 categories, so there are 57+ columns with a "0" in the field. My current query is:
mysql_query("SELECT AVG(category_1 + category_2 + category_3 + category_4 + category_5 + category_6 + category_7 + category_8 + category_9 + category_10 + category_11 + category_12 + category_13 + category_14 + category_15 + category_16 + category_17 + category_18 + category_19 + category_20 + category_21 + category_22 + category_23 + category_24 + category_25 + category_26 + category_27 + category_28 + category_29 + category_30 + category_31 + category_32 + category_33 + category_34 + category_35 + category_36 + category_37 + category_38 + category_39 + category_40 + category_41 + category_42 + category_43 + category_44 + category_45 + category_46 + category_47 + category_48 + category_49 + category_50 + category_51 + category_52 + category_53 + category_54 + category_55 + category_56 + category_57 + category_58 + category_59 + category_60) as 'cat_avg' FROM products.rankings WHERE product_id = '$product_id'");
With this, I'm just getting the sum of the columns, not the AVG. Maybe this has something to do with selecting rows instead of columns, I'm not sure. I tried SUM as well, instead of AVG, same thing.
I'm not really sure where to go from here. What i would like is the Average ranking across all columns for one product, where the column doesn't equal 0. So if a product_id 123 is ranked 7, 9 and 11, and then the other 57 columns are 0, the average returned would be 9 ((7+9+11)/3), not .45 ((7+9+11+0+0+0....+0))/60)
Note: I did not design this DB, I'm sure there is a better way to design it, but at this point it's too deeply integrated to change up quickly.
This may be a lot of stress on the query, but I don't know many other ways to do this, given the schema you have to work with.
One option is to sub-query the columns and union them, where the given columns are not 0:
SELECT AVG(
SELECT *
FROM (
SELECT category_1 AS category FROM table
UNION
SELECT category_2 AS category FROM table
UNION
...
) cats
WHERE category <> 0
)
FROM products.rankings
WHERE product_id = '$product_id'
It probably makes more sense to do this math within the page (assuming PHP given the query decorations) and on a per-row basis. Doing the above will put a lot of strain on the server depending the number of rows we're talking.
Restructured the whole DB... wasn't as bad as I though, just did a bunch of MySQL queries/updates that got me what I needed. Strained the server for a few hours, but it was well worth it in the end.