How to merge this two query statement into one query statement - mysql

1. SELECT * FROM instalmentsdetails WHERE instalmentName='Third Installment'AND studentFeeId='1'
2. select max(`receiptNo`)as `receiptNo` FROM instalmentsdetails
Table instalmentsdetails
instalmentsDetailsId
studentFeeId
receiptNo
instalmentName
amount
dueDate
fineAmt
waivedAmt
scholarShip
grandTotal
status
Little confused .How to merge this two query statement into one query statement
P.S: One statement checks for the condition and the other checks for the max of receiptNo in that table
I want both the values in one query

Is this what you want?
SELECT max(`receiptNo`) as `receiptNo`
FROM instalmentsdetails
WHERE instalmentName='Third Installment' AND studentFeeId='1'
Update: how about this:
SELECT *
FROM instalmentsdetails as inds
INNER JOIN (
SELECT max(`receiptNo`) as `maxreceiptNo`
FROM instalmentsdetails
) as maxt
WHERE inds.instalmentName='Third Installment' AND inds.studentFeeId='1'
This applies the filter to the table, then adds an extra column (the maximum receiptNo)

Assuming the goal is to get:
a list of instalmentsdetails with specific a instalmentName and studentFeeId
global maximum
 
SELECT *, 0 AS receiptNo FROM instalmentsdetails WHERE instalmentName='Third Installment'AND studentFeeId='1'
UNION
select *, max(`receiptNo`) as `receiptNo` FROM instalmentsdetails
Update
Apparently the OP simply wants to consolidate separate query results into a single row. In that case:
SELECT
*,
(SELECT max(`receiptNo`) FROM instalmentsdetails) AS maxReceiptNo
FROM instalmentsdetails WHERE instalmentName='Third Installment'AND studentFeeId='1'

From all the reading, Matt is correct, but maybe I can help explain what he's doing...
The first part of the query (From InstalmentsDetails WHERE YourCondition) will get all records that qualify for the condition.
THEN, by doing a JOIN to the second query (select max( 'receiptNo' ) from... with no where clause ) will ALWAYS return a single row, single column of the maximum receipt without regard to ANY criteria.
This creates an implied Cartesian result. Join everything in the first table with every record in the second. Since there is no explicit join condition, every row will get the same "max()" value as a returned column. And since there will only be one record in the select max() call, you never worry about duplicates.
Now, if you wanted the maximum receipt within the same criteria, you would just copy that same criteria to the select max() query portion.

Related

What is the correct MySQL syntax for a query with a COUNT from another table as a column?

Here is a query I've used that almost does what I want:
SELECT *, COUNT(p.prize_id) as number_prizes
FROM tbl_draw d
INNER JOIN tbl_prize p ON p.draw_id=d.draw_id
WHERE d.draw_id={$draw_id}
The key point is that it counts the number of items from tbl_prize that matches on draw_id and presents that number as a new column 'number_prizes' in the result set. For this query, the result set is a single row, because of the final WHERE clause that matches on a specific draw_id.
I want it to return ALL of the rows from tbl_draw with that same calculation per row. My problem is that when I remove the final clause "WHERE d.draw_id={$draw_id}", the result collapses all the rows into one, and is only sending back the first such row found in tbl_draw and with 'number_prizes' being a total of all
How can I phrase the query better?
You need to add a group by clause, naming all columns, eg:
<your query>
group by col1, col2, ... -- list all other columns
As said above, you should use the group by after the end of your query, like this:
SELECT *, COUNT(p.prize_id) as number_prizes
FROM tbl_draw d
INNER JOIN tbl_prize p ON p.draw_id=d.draw_id
WHERE d.draw_id={$draw_id}
GROUP BY col1, col2, col3, coln.....
And, if you want the id from tbl_draw, your SELECT must be like:
SELECT d.id as draw_id, *, COUNT(p.prize_id) as number_prizes
I strongly recommend that you do not use SELECT *, ... here. List all of the columns that form the groups within the SELECT clause, then repeat that list within GROUP BY.
Here's why: "SELECT * will work only until someone adds a column to that table!" Which of course will happen someday.
Then, all of the sudden, your query will start failing, because * references this new column (which presumably you don't care about anyway ...), which is not in the GROUP BY list as is required.
Always specify exactly what columns (and aggregate functions ...) your query needs. You'll be very glad you did. (And so will your co-workers!)

Why does HAVING MAX() return a different value than SELECT MAX()?

I have a table log that contains, among others, a DateTime column called TimeOfLog and a foreign key Logger_ID.
What I was trying to do was get the newest entry per Logger_ID.
SELECT l.TimeOfLog AS TimeOfLog, l.Logger_ID AS Logger_ID
FROM `log` `l`
GROUP BY l.Logger_ID
HAVING MAX(l.TimeOfLog)
this however returns more or less a random TimeOfLog belonging to that Logger_ID. If I then run
SELECT MAX(l.TimeOfLog) AS TimeOfLog, l.Logger_ID AS Logger_ID
FROM `log` `l`
GROUP BY l.Logger_ID
I get the expected, newest, result. However, I'm pretty sure the Logger_ID is not the one belonging to that TimeOfLog.
Why is that/What am I misunderstanding here?
To get the maximum row, don't think group by; think filtering. Here is one method:
select l.*
from log l
where l.timeoflog = (select max(t2.timeoflog)
from log l2
where l2.logger_id = l.logger_id
);
If you just want the maximum time, then aggregation is appropriate:
select logger_id, max(timeoflog)
from log l
group by logger_id;
You have the expression:
HAVING MAX(l.TimeOfLog)
This just checks that the maximum is not 0 or NULL.
You are misunderstarding how GROUP BY AND HAVING works.
GROUP BY groups all rows that have same values in columns specified columns together into one group. If you select one column that is not mentioned in GROUP BY without using agregate function, you will randomly get one value from the grouped rows.
If you use agregate function like MAX() then the function is applied on all grouped rows and then result is selected.
HAVING is a filter similar to WHERE but while WHERE is applied before grouping the HAVING filter is applied after grouping.
You can use aggregate functions there. The correct usage of having might be for example
SELECT column,
FROM table
GROUP BY column
HAVING COUNT(*) > 1
This query would only select values of column that are present more than once.
In your example the MAX(c.TimeOfLog) will always be true as long as c.TimeOfLog is not empty for at least one row in group so it won't filter anything.

Subquery returns more rows than straight same query in MySQL

I want to remove duplicates based on the combination of listings.product_id and listings.channel_listing_id
This simple query returns 400.000 rows (the id's of the rows I want to keep):
SELECT id
FROM `listings`
WHERE is_verified = 0
GROUP BY product_id, channel_listing_id
While this variation returns 1.600.000 rows, which are all records on the table, not only is_verified = 0:
SELECT *
FROM (
SELECT id
FROM `listings`
WHERE is_verified = 0
GROUP BY product_id, channel_listing_id
) AS keepem
I'd expect them to return the same amount of rows.
What's the reason for this? How can I avoid it (in order to use the subselect in the where condition of the DELETE statement)?
EDIT: I found that doing a SELECT DISTINCT in the outer SELECT "fixes" it (it returns 400.000 records as it should). I'm still not sure if I should trust this subquery, for there is no DISTINCT in the DELETE statement.
EDIT 2: Seems to be just a bug in the way phpMyAdmin reports the total count of the rows.
Your query as it stands is ambiguous. Suppose you have two listings with the same product_id and channel_id. Then what id is supposed to be returned? The first, the second? Or both, ignoring the GROUP request?
What if there is more than one id with different product and channel ids?
Try removing the ambiguity by selecting MAX(id) AS id and adding DISTINCT.
Are there any foreign keys to worry about? If not, you could pour the original table into a copy, empty the original and copy back in it the non-duplicates only. Messier, but you only do SELECTs or DELETEs guaranteed to succeed, and you also get to keep a backup.
Assign aliases in order to avoid field reference ambiguity:
SELECT
keepem.*
FROM
(
SELECT
innerStat.id
FROM
`listings` AS innerStat
WHERE
innerStat.is_verified = 0
GROUP BY
innerStat.product_id,
innerStat.channel_listing_id
) AS keepem

Specific where clause in Mysql query

So i have a mysql table with over 9 million records. They are call records. Each record represents 1 individual call. The columns are as follows:
CUSTOMER
RAW_SECS
TERM_TRUNK
CALL_DATE
There are others but these are the ones I will be using.
So I need to count the total number of calls for a certain week in a certain Term Trunk. I then need to sum up the number of seconds for those calls. Then I need to count the total number of calls that were below 7 seconds. I always do this in 2 queries and combine them but I was wondering if there were ways to do it in one? I'm new to mysql so i'm sure my syntax is horrific but here is what I do...
Query 1:
SELECT CUSTOMER, SUM(RAW_SECS), COUNT(*)
FROM Mytable
WHERE TERM_TRUNK IN ('Mytrunk1', 'Mytrunk2')
GROUP BY CUSTOMER;
Query 2:
SELECT CUSTOMER, COUNT(*)
FROM Mytable2
WHERE TERM_TRUNK IN ('Mytrunk1', 'Mytrunk2') AND RAW_SECS < 7
GROUP BY CUSTOMER;
Is there any way to combine these two queries into one? Or maybe just a better way of doing it? I appreciate all the help!
There are 2 ways of achieving the expected outcome in a single query:
conditional counting: use a case expression or if() function within the count() (or sum()) to count only specific records
use self join: left join the table on itself using the id field of the table and in the join condition filter the alias on the right hand side of the join on calls shorter than 7 seconds
The advantage of the 2nd approach is that you may be able to use indexes to speed it up, while the conditional counting cannot use indexes.
SELECT m1.CUSTOMER, SUM(m1.RAW_SECS), COUNT(m1.customer), count(m2.customer)
FROM Mytable m1
LEFT JOIN Mytable m2 ON m1.id=m2.id and m2.raw_secs<7
WHERE TERM_TRUNK IN ('Mytrunk1', 'Mytrunk2')
GROUP BY CUSTOMER;

Dividing values in a column by the number of rows returned in the query. Can it be done in a single query?

Can I divide the values in a column by the number of rows returned in the query, using a single query?
For example, I select some numeric value from a table based on some condition:
select value from table where ...
Let's say it returns N rows and I want the returned values divided by the number of rows returned:
select value / N from table where ...
It can be done with several queries (e.g. after the first query, I query the number of rows and do the query again). But can it be done in a single query with some SQL trick without query condition duplication, so that the actual selection (the WHERE part) which may be complicated runs only once?
You can do it in a single query, but as far as I know, with mysql you have to repeat the condition:
select
value/#cnt from
table1
INNER JOIN (select #cnt = count(*)
FROM table1 WHERE [the same condition as in main query]) ON (1=1)
WHERE condition
Or you can just
SELECT value/(SELECT COUNT(*) FROM table1 WHERE ...)
FROM table1
WHERE ...
I believe optimizer should generate the same execution plan for both queries.