I have 2 tables.
CREATE TABLE $media_table (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`options` longtext DEFAULT NULL,
`order_id` int(11) unsigned DEFAULT NULL,
`player_id` int(11) unsigned NOT NULL,
PRIMARY KEY (`id`))
CREATE TABLE $category_table (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`category` varchar(300) DEFAULT NULL,
`media_id` int(11) unsigned DEFAULT NULL,
PRIMARY KEY (`id`))
I get id, options, category for rows matching category 'foo','bar'. I also use limit to get only x number of results.
SELECT mt.id, mt.options, ct.category
FROM $media_table as mt
LEFT JOIN $category_table as ct
ON mt.id = ct.media_id
WHERE mt.player_id = %d AND ct.category IN ('foo','bar')
GROUP BY ct.media_id
ORDER BY mt.order_id
LIMIT $limit
This works as intended. But I dont know how to get total number of results?
I tried this but the count is not correct.
SELECT COUNT(mt.id), ct.category
FROM $media_table as mt
LEFT JOIN $category_table as ct
ON mt.id = ct.media_id
WHERE mt.player_id = %d AND ct.category IN ('foo','bar')
GROUP BY ct.media_id
Where I select all results without the limit (in my previous query) the count is correct.
If I had only one table with primary key id I would do this to get count:
SELECT COUNT(id) FROM table
I dont know how to apply the same to my query.
Edit: I found my answer here select count(*) from select
Question 1: Are you looking at the raw results of the query using a tool like phpMyAdmin or MySQL WorkBency or what?
Question 2: Will the ultimate query results be delivered to the client via a web browser or what?
Answer 1: "The SUM() function returns the total sum of a numeric column."
SELECT SUM(column_name) FROM table_name WHERE condition;
Answer Possibility 2: If the results will be delivered in a web browser you should be able to use PHP or some other server side language like MS Active Server Pages to add up he "COUNT" field of each result.
Answer Possibility 3: Alternative 1: Export the results to a CVS file and import into a spreadsheet.
Maybe some of these suggestions will get the wheels turning and help you find the solution you are looking for.
Related
hello I have a SQL DB with two tables.
common_fee_collection //parent table
common_fee_collection_headwise //child table
now the structure of this two tables are like this
CREATE TABLE `common_fee_collection` ( `id` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT, `admno` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL, `amount` double(13,2) NOT NULL );
this table contains rows which's amount column represent the sum of total amount in a lifetime
id = it's an auto increment ID with unique data
admno = a unique admission number
amount = the total amount combined from table common_fee_collection_headwise.amount from all the rows in common_fee_collection_headwise.amount
CREATE TABLE `common_fee_collection_headwise` ( `id` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT, `moduleId` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL, `receiptId` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL, `amount` double(13,2) NOT NULL )
id AUTO_INCREMENT integer data
receiptId =this is the foreign key from common_fee_collection.id
amount= amount in a perticular transaction at a perticular time
now the question is I want to get the rows where common_fee_collection.amount is not equals SUM(common_fee_collection_headwise.amount). means the rows which are mismatched amount.
I have tried these three query but it gives wrong output or errors
1> SELECT * FROM common_fee_collection WHERE amount <> SUM(common_fee_collection_headwise.amount) AND id=common_fee_collection_headwise.receiptId;
this code gives error #1111 - Invalid use of group function
2> SELECT * FROM common_fee_collection as com WHERE amount<>SUM(common_fee_collection_headwise.amount) AND id=common_fee_collection_headwise.receiptId
this code gives error #1111 - Invalid use of group function
3> SELECT * FROM common_fee_collection AS a JOIN common_fee_collection_headwise as b ON a.id=b.receiptId HAVING SUM(b.amount) <> a.amount
this code returns the first row from common_fee_collection which is not proper return which i want.... i don't know my queries are right or wrong but i hope i was clear about my problem and you will try to help.
You can first aggregate them and then can compare -
SELECT CFC.`id`, CFC.`amount`, CFCH.HEADWISE_AMOUNT
FROM `common_fee_collection` CFC
LEFT JOIN (SELECT `receiptId`, SUM(`amount`) HEADWISE_AMOUNT
FROM `common_fee_collection_headwise`
GROUP BY `receiptId`) CFCH ON CFC.`id` = CFCH.`receiptId`
WHERE CFC.`amount` <> CFCH.HEADWISE_AMOUNT
Try this query:
SELECT cfc.*
FROM common_fee_collection AS cfc
WHERE cfc.amount != (
SELECT SUM(cfch.amount)
FROM common_fee_collection_headwise AS cfch
WHERE cfch.receiptId = cfc.id
GROUP BY cfch.receiptId
);
You can see the result in this DBfiddle.
Note: I see a difference between the datatypes of the fields in foreign key between the two tables: common_fee_collection.id bigint and common_fee_collection_headwise.receiptId varchar(255)
I have the following (simplified) database schema:
CREATE TABLE IF NOT EXISTS `wm_renderings` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`formula_id` int(11) NOT NULL,
`creation_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`svg` text COLLATE utf8_bin NOT NULL,
PRIMARY KEY (`id`),
KEY `formula_id` (`formula_id`)
);
where formula_id is a foreign key.
I want to get the latest rendering for every formula_id. But when I write
SELECT `id`, `formula_id`, `svg`
FROM `wm_renderings`
GROUP BY `formula_id`
ORDER BY `creation_time` DESC
I would get a "random" rendering for each formula_id.
My approach would be to get all formula ids and then send a query for every single formula_id:
SELECT `id`, `formula_id`, `svg`
FROM `wm_renderings`
WHERE `formula_id` = 42
ORDER BY `creation_time` DESC
LIMIT 1
However, that would be a lot of queries.
Can I get the same with only one query?
The way to get the max/latest per group could be done is various way and one such way is to use left join
select t1.* from wm_renderings t1
left join wm_renderings t2 on t1.formula_id = t2.formula_id
and t1.creation_time < t2.creation_time
where t2.id is null
Here is the documentation on it
http://dev.mysql.com/doc/refman/5.0/en/example-maximum-column-group-row.html
Left join and Uncorrelated subs-query are considered to be better in terms of performance.
I have this query:
SELECT `Stocks`.`id` AS `Stocks.id` , `Locations`.`id` AS `Locations.id`
FROM `rowiusnew`.`c_stocks` AS `Stocks`
LEFT JOIN `rowiusnew`.`g_locations` AS `Locations` ON ( `Locations`.`ref_id` = `Stocks`.`id` AND `Locations`.`ref_type` = 'stock' )
GROUP BY `Stocks`.`id`
HAVING `Locations.id` IS NOT NULL
This returns 0 results.
When I add
ORDER BY Locations.id
to the exactly same query, I correctly get 3 results.
Noteworthy: When I discard the GROUP BY clause, I get the same 3 results. The grouping is necessary for the complete query with additional joins; this is the simplified one to demonstrate the problem.
My question is: Why do I not get a result with the original query?
Note that there are two conditions in the JOIN ON clause. Changing or removing the braces or changing the order of these conditions does not change the outcome.
Usually, you would suspect that the field id in g_locations is sometimes NULL, thus the ORDER BY clause makes the correct referenced result be displayed "at the top" of the group dataset. This is not the case; the id field is correctly set up as a primary key field and uses auto_increment.
The EXPLAIN statement shows that filesort is used instead of the index in those cases when I actually get a result. The original query looks like this:
The modified, working query looks like this:
Below is the table definitions:
CREATE TABLE IF NOT EXISTS `c_stocks` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`id_stock_type` int(10) unsigned DEFAULT NULL,
`name` varchar(255) DEFAULT NULL,
`locality` varchar(100) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `StockType_idx` (`id_stock_type`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE IF NOT EXISTS `g_locations` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(255) DEFAULT NULL,
`ref_type` enum('stock','object','branch') DEFAULT NULL,
`ref_id` int(10) unsigned DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `UniqueLocation` (`ref_type`,`ref_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
The ref_id field features a long comment that I omitted in this definition.
After being unable to reproduce the error on SQLFiddle.com and also on my second computer, I realized that there must be a bug involved.
Indeed, my used version 5.6.12 suffers from this bug:
Some LEFT JOIN queries with GROUP BY could return incorrect results. (Bug #68897, Bug #16620047)
See the change log of MySQL 5.6.13: http://dev.mysql.com/doc/relnotes/mysql/5.6/en/news-5-6-13.html
An upgrade to 5.6.17 solved my problem. I am not getting the results I expect, independent of ORDER clauses and aggregate functions.
Remove
having locations.id is not null
instead use
where locations.id is not null
locations.id is not null is not a problem for the grouping - you don't want them included at all.
Also, you need to do something with the locations.id since it isn't in the group by clause. Do you want "max" locations.id?
so your query now becomes:
SELECT `Stocks`.`id` AS `Stocks.id` , max(`Locations`.`id`) AS `Locations.id`
FROM `rowiusnew`.`c_stocks` AS `Stocks`
LEFT JOIN `rowiusnew`.`g_locations` AS `Locations` ON ( `Locations`.`ref_id` = `Stocks`.`id` AND `Locations`.`ref_type` = 'stock' )
WHERE `Locations.id` IS NOT NULL
GROUP BY `Stocks`.`id`
Make those changes and it should work better for you.
FYI: I think that by putting in the order by clause, you are allowing the engine to guess what you want for the locations.id, otherwise it has no clue. In something other than MYSQL, it wouldn't run at all.
I have a query that is not grouping properly and returning the wrong results and I can't figure out what the problem is.
The query is shown below. FYI - It's not obvious in it's current form why I need the group by because I've removed all other parts of the query to get to the most basic form where I see a problem.
SELECT * FROM (
SELECT *
FROM notifications n
WHERE 1
-- and group_id = '5b35c8eb075881f8bbdfbcb36b052aa7'
GROUP BY `from`
) t
WHERE group_id = '5b35c8eb075881f8bbdfbcb36b052aa7'
The problem is that when I use put the where on the inside subquery (currently commented out), for this case, I end up with 4 results. Each of the 4 results have a different "from" value so should be listed separately. When I put the where on the outside of the subquery I end up with 3 results.
For completeness the table definition is:
CREATE TABLE `notifications` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`mem_id` int(10) unsigned DEFAULT NULL,
`type` varchar(255) NOT NULL,
`from` varchar(255) DEFAULT NULL,
`entry_id` int(11) DEFAULT NULL,
`parent_id` int(11) DEFAULT NULL,
`table_id` varchar(255) DEFAULT NULL,
`created_at` datetime DEFAULT NULL,
`emailed` tinyint(1) DEFAULT NULL,
`read` tinyint(1) NOT NULL,
`group_id` char(32) NOT NULL,
PRIMARY KEY (`id`),
KEY `mem_id` (`mem_id`),
KEY `created_at` (`created_at`),
KEY `entry_id` (`entry_id`),
KEY `parent_id` (`parent_id`),
KEY `group_id` (`group_id`)
)
Any ideas what could cause this? I'm completely stumped. At this point I'm ready to attribute it to some bug in mysql but that also seems unlikely.
Update
I wasn't clear by what I meant by "wrong results" There were 7 records in the data set with this group_id. There were 2 records with a unique "from" and 5 more records with 2 other "from" ids (one had 3 records, one had 2).
Doing the where for the group by on the inside resulted in in the 4 records that I wanted. I don't care about which row was selected as the result because I'm doing other sums/counts which I excluded from the example because it wasn't directly relevant to the problem.
If I do the where on the outer group by one of the two records with a single "from" did not return at all.
I'll try to update with a sqlfiddle (didn't know about that!) - the issue is that this database I was testing on is wiped daily so I don't have the original data, I'll see if I can reproduce.
update #2
I noticed that in my questions, I've been referring to inner and outer group by - the group by is always on the inner query it's just where the "where" is. I've tried to adjust the phrasing. Again, it's not immediately obvious why I care about the location of the where - but in my final use case, I need the selection to happen on the outside (I'm building a count of notifications that are read/unread and I need a count both per member and total per message - eg the group_id)
sqlfiddle: http://www.sqlfiddle.com/#!2/7d746/5
screenshot of query with inner where:https://www.evernote.com/shard/s48/sh/e355e96e-e48d-4550-bbaf-ffb18bc0bb9c/08e2454867e00e3a05535303429748f1
screenshot of query with outer where:https://www.evernote.com/shard/s48/sh/60b10427-e417-4196-8b92-7d6d8031d21e/c779bc9c46d23472983ac6fa0d25e42d
With the sqlfiddle I get back 4 results each time! Which leads me more to think it's a server issue. We're running MySQL 5.5.28-29.2 Percona Server (GPL), Release rel29.2, Revision 360
This query:
SELECT *
FROM notifications n
WHERE 1
GROUP BY `from`
is simply wrong in ANSI SQL and on almost all DBMS (oracle, postgres, MS SQL etc.).
It runs on MySql only because of their nonstandard group by extension
See this link: http://dev.mysql.com/doc/refman/5.0/en/group-by-extensions.html
Hovever they warn about something:
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.
Because of this "feature" your query (select from select * group by) is unpredicable, results are dependent on the order of records in the table.
Take a look at this simple demo: http://www.sqlfiddle.com/#!2/b762e/2
There are two identic tables in this demo, with the same content, the only difference is a physical rows order. And the same queries give completely different results.
---- EDIT how to solve this problem -----
To solve this problem in your query, just add both columns to the GROUP BY clause.
select * FROM (
SELECT * FROM notifications n
GROUP BY `from`, `group_id`
) x
WHERE group_id = 'A';
select * FROM (
SELECT * FROM notifications n
WHERE group_id = 'A'
GROUP BY `from`, `group_id`
) x
Above two queries give always the same results for columns from and group_id, other columns (not included in the GROUP BY clause`) can be random.
Take a look at simple demo --> http://www.sqlfiddle.com/#!2/5d19b/5
I've been working on a small Perl program that works with a table of articles, displaying them to the user if they have not been already read. It has been working nicely and it has been quite speedy, overall. However, this afternoon, the performance has degraded from fast enough that I wasn't worried about optimizing the query to a glacial 3-4 seconds per query. To select articles, I present this query:
SELECT channelitem.ciid, channelitem.cid, name, description, url, creationdate, author
FROM `channelitem`
WHERE ciid NOT
IN (
SELECT ciid
FROM `uninet_channelitem_read`
WHERE uid = '1030'
)
AND (
cid =117
OR cid =308
OR cid =310
)
ORDER BY `channelitem`.`creationdate` DESC
LIMIT 0 , 100
The list of possible cid's varies and could be quite a bit more. In any case, I noted that about 2-3 seconds of the total time to make the query is devoted to "ORDER BY." If I remove that, it only takes about a half second to give me the query back. If I drop the subquery, the performance goes back to normal... but the subquery didn't seem to be problematic until just this afternoon, after working fine for a week or so.
Any ideas what could be slowing it down so much? What might I do to try to get the performance back up to snuff? The table being queried has 45,000 rows. The subquery's table has fewer than 3,000 rows at present.
Update: Incidentally, if anyone has suggestions on how to do multiple queries or some other technique that would be more efficient to accomplish what I am trying to do, I am all ears. I'm really puzzled how to solve the problem at this point. Can I somehow apply the order by before the join to make it apply to the real table and not the derived table? Would that be more efficient?
Here is the latest version of the query, derived from suggestions from #Gordon, below
SELECT channelitem.ciid, channelitem.cid, name, description, url, creationdate, author
FROM `channelitem`
LEFT JOIN (
SELECT ciid, dateRead
FROM `uninet_channelitem_read`
WHERE uid = '1030'
)alreadyRead ON channelitem.ciid = alreadyRead.ciid
WHERE (
alreadyRead.ciid IS NULL
)
AND `cid`
IN ( 6648, 329, 323, 6654, 6647 )
ORDER BY `channelitem`.`creationdate` DESC
LIMIT 0 , 100
Also, I should mention what my db structure looks like with regards to these two tables -- maybe someone can spot something odd about the structure:
CREATE TABLE IF NOT EXISTS `channelitem` (
`newsversion` int(11) NOT NULL DEFAULT '0',
`cid` int(11) NOT NULL DEFAULT '0',
`ciid` int(11) NOT NULL AUTO_INCREMENT,
`description` text CHARACTER SET utf8 COLLATE utf8_unicode_ci,
`url` varchar(222) DEFAULT NULL,
`creationdate` datetime DEFAULT NULL,
`urgent` varchar(10) DEFAULT NULL,
`name` varchar(255) CHARACTER SET utf8 COLLATE utf8_unicode_ci DEFAULT NULL,
`lastchanged` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
`author` varchar(255) NOT NULL,
PRIMARY KEY (`ciid`),
KEY `newsversion` (`newsversion`),
KEY `cid` (`cid`),
KEY `creationdate` (`creationdate`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=1638554365 ;
CREATE TABLE IF NOT EXISTS `uninet_channelitem_read` (
`ciid` int(11) NOT NULL,
`uid` int(11) NOT NULL,
`dateRead` datetime NOT NULL,
PRIMARY KEY (`ciid`,`uid`),
KEY `ciid` (`ciid`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
It never hurts to try the left outer join version of such a query:
SELECT ci.ciid, ci.cid, ci.name, ci.description, ci.url, ci.creationdate, ci.author
FROM `channelitem` ci left outer join
(SELECT ciid
FROM `uninet_channelitem_read`
WHERE uid = '1030'
) cr
on ci.ciid = cr.ciid
where cr.ciid is null and
ci.cid in (117, 308, 310)
ORDER BY ci.`creationdate` DESC
LIMIT 0 , 100
This query will be faster with an index on uninet_channelitem_read(ciid) and probably on channelitem(cid, ciid, createddate).
The problem could be that you need to create an index on the channelitem table for the column creationdate. Indexes help a database to run queries faster. Here is a link about MySQL Indexing