MYSQL: GROUP BY on all values except 0 and null? - php

I have a simple SQL Query:
SELECT tid,
COUNT(*) AS bpn
FROM mark_list
WHERE userid = $userid
GROUP BY tid
Now the column tid is basically a category list associated with each entry. The categories are unique numeric values.
What I am trying to do is get an overall count of how many records there as per userid, but I only want to count an entire category one time (meaning if category 3 has 10000 records, it should only receive a count of 1).
The caveat is that sometimes the category is listed as null or sometimes a 0. If the item has either a 0 or a null, it has no category and I want them counted as their own separate entities and not lumped into a single large category.

Wheeee!
SELECT SUM(`tid` IS NULL) AS `total_null`,
SUM(`tid` = 0) AS `total_zero`,
COUNT(DISTINCT `tid`) AS `other`
FROM `mark_list`
WHERE `user_id` = $userid
Edit: note that if total_zero is greater than 0, you will have to subtract one from the "other" result (because tid=0 will get counted in that column)

You can alter the query to not take into account those particular values (via the WHERE clause), and then perhaps run a separate query that ONLY takes into account those values.
There may be a way to combine it into only one query, but this way should work, too.

Related

Summing up values from a single table column using PHP

I would like you know how I can sum up all values from a single table column based on a specific constraint. What I mean is this, imagine a table called payments, the payments table has three columns; ID, type of payment and amount. ID is not a primary key so it can duplicate. So let's say there are four entries under one particular ID and I want to get the total for amount for that ID. How can I do it? Thought a while loop would work but tried everything I could think of and it didn't. Please help! Final school project
If you are using mysql you can use the sum function as follows:
SELECT SUM(t1.ID) FROM db1.tblmoney AS t1 WHERE t1.ID = '1';
This will select the sum total of column "ID" in all rows within db1.tblmoney with the ID of 1. If on the other hand you are trying to get a count of the rows with that ID you can use this:
SELECT COUNT(t1.*) FROM db1.tblmoney AS t1 WHERE t1.ID = '1';
The different in these two statements is SUM with get the added values of all ID
So if you have 2 rows of id ='1' you will get 2 if you have two rows of id = '2' you will get 4
Whereas with Count() it will count the number of rows matching your select: 2 rows of id ='1' you will get 2 if you have two rows of id = '2' you will get 2.

How to retrieve count values as multiple columns using group by in single query in MySQL?

I am writing a complex MySQL query. My actual query is more complex than I mentioned below.
I have a table named example and columns are id, name, option_1, option_2 . Of course id column is PK . I want to retrieve like this:
SELECT `id`,`name`,count(`option_1`),count(`option_2`)
My problem is I want to use "GROUP BY `id`" for count(`option_1`) and "GROUP BY `name`" for count(`option_2`) respectively. Now I have to break down it into multiple code in my php code.
How can I achieve what I want in a single query?
What you're asking for doesn't make a ton of sense. You want option 1 grouped by id and option 2 grouped by name, and you want to show all four columns in one result set.
First of all, if id is a primary key, then the count will just be the number of rows in the table since there will be no duplicate ids.
Second, even if id wasn't a primary key, and there were duplicate values, the grouping is different, so the counts represented in your result set would be grouped incorrectly.
Given that id is a primary key, perhaps your intention is actually to get a total count of the rows in the table. Perhaps this query would suit your needs?
SELECT
name,
COUNT(option_2) AS options
FROM
example
GROUP BY
name
UNION ALL
SELECT
'Total' AS name,
COUNT(*) AS options
FROM
example
This should get you a count of all the option_2 values, grouped by name, with the final row having a name of 'Total' and the count being the total number of rows in the table.
Aside from that, I'm not sure you're going to find the answer you're looking for due to the problems you would encounter matching up groupings.

Is my JOIN + GROUP BY ... HAVING COUNT query correct?

I'm new to SQL and I want to implement the following query:
I've got two tables, LicenseTbl and UnlockTbl:
LicenseTbl contains information about a purchased software license:
LicenseID, ProgramID, Owner, Location, OrderNo, BlockTime
UnlockTbl contains information about a specific software registration:
UnlockID, LicenseID (foreign key into LicenseTbl), Timestamp, SerialNo, Key, UninstallTime
where BlockTime and UninstallTime contain a timestamp if the license was blocked or the software uninstalled and NULL otherwise.
I want to devise a query that gives me ALL LicenseIDs for which the following conditions hold:
belongs to a given customer,
is not blocked,
is either not listed in the UnlockTbl or there are < X different SerialNo's in lines which are not marked as uninstalled.
I have written this, but I'm not sure if it is absolutely correct (it's one of my first SQL queries ever):
SELECT LicenseID FROM LicenseTbl
JOIN UnlockTbl
ON (LicenseTbl.LicenseID = UnlockTbl.LicenseID)
WHERE LicenseTbl.OrderNo = '$givenOrderNo'
AND LicenseTbl.Owner = '$givenOwner'
AND LicenseTbl.Location = '$givenLocation'
AND LicenseTbl.BlockTime IS NULL
AND UnlockTbl.UninstallTime IS NULL
GROUP BY LicenseTbl.LicenseID, UnlockTbl.Key
HAVING COUNT(*) < $X
(which is supposed to mean, list all licenses which have only been used less than X times simultaneously. I would prefer those that have been used the least first but don't know how to sort like that.)
This is a good start, but I would change the query to the following...
SELECT
LicenseID
FROM
LicenseTbl
LEFT JOIN
UnlockTbl
ON UnlockTbl.LicenseID = LicenseTbl.LicenseID
AND UnlockTbl.UninstallTime IS NULL
WHERE
LicenseTbl.OrderNo = '$givenOrderNo'
AND LicenseTbl.Owner = '$givenOwner'
AND LicenseTbl.Location = '$givenLocation'
AND LicenseTbl.BlockTime IS NULL
GROUP BY
LicenseTbl.LicenseID
HAVING
COUNT(DISTINCT UnlockTbl.SerialNo) < $X
ORDER BY
COUNT(DISTINCT UnlockTbl.SerialNo)
1). LEFT JOIN
A LEFT JOIN ensures that all rows in LicenseTbl are returned, even if there are no matches in the UnlockTbl table. (If there are no matches, the UnlockTbl table's values are all represented as NULL.)
2). UnlockTbl.UninstallTime IS NULL in the JOIN and not the WHERE
The WHERE clause is applied after the JOIN. This means that any records in UnlockTbl where UninstallTime have a real value (NOT NULL) get joined and then get filtered out. This in turn means that if all the relevant records in UnlockTbl have a non-NULL value in UninstallTime, all the rows for that License will get filtered.
3). GROUP BY on just the license, not the Key.
Simply, I don't know why you had it there, and it doesn't appear in the English description of what you want.
As you want a list of LicenseIDs, grouping by only that field ensures that you get one record per LicenseID.
4). HAVING clause modified to look at COUNT(DISTINCT SerialNo)
COUNT(*) counts all records. Even if there was no match (All the UnlockTbl values appearing as NULL), this would return 1.
COUNT(SerialNo) counts only records where SerialNo is NOT NULL. If there was no match (All the UnlockTbl values appearing as NULL), this would return 0.
COUNT(DISTINCT SerialNo) also counts only records where SerialNo is NOT NULL, but treats duplicates of the sme value as just 1 entry.
5). ORDER BY COUNT(DISTINCT SerialNo)
Takes the same value as is being filtered in the HAVING clause, and orders by it.

MySQL Join table and get results that don't exist in one

I have two tables, one that has a foreign key from the other. I want to get all records that don't exist in the foreign table, based on certain criteria.
Here are the tables I have:
item_setting
setting_id
category_id
item
item_id
setting_id
name
expired_dt
Here's the query I'm using now:
SELECT
iset.setting_id
FROM
item_settings iset
LEFT OUTER JOIN
item i ON i.setting_id = iset.setting_id
WHERE
iset.category_id = '5' AND i.setting_id is null
This query works in providing any setting_id's that do not have a record in the item's table within a specific category.
However, now I want to include cases where the expired_dt less than than time() (meaning it's past expired). In otherwords, I would think to add this:
WHERE
iset.category_id = '5' AND (i.setting_id is null OR i.expired_dt < '".time()."')
However, this doesn't work, it returns all the records.
Any suggestions? Maybe I'm completely over complicating this.... I just want to return the setting_id's from the item_settings table, where the expired_dt associated in the item table is expired or if it does not even exist in the item table.
Thank you!
Try moving the timestamp condition into the join clause. Something like
item_settings iset
LEFT OUTER JOIN
item i ON i.setting_id = iset.setting_id and i.expired_dt > time()

How to count the number of rows before a given row in MySQL with CodeIgniter?

Simply put, how can I count how many rows there are before a certain row. I'm using incremental ID's, but rows are deleted a random, so just checking to see what the ID is won't work.
If I have, say, 30 rows, and I've selected one based on a name (or anything really), how many rows are there before that one? It could be 16, 1, 12, or anything.
I'm using MySQL and CodeIgniter.
I assume your primary key column has datatype integer
SELECT COUNT(*) FROM `table`
WHERE id < (SELECT id FROM `table` WHERE `conditions are met for specific row`)
Assuming it's an auto_increment column, deleted rows won't be filled in again so this should do the job.
SELECT COUNT(*) FROM table WHERE id_column < your_selected_row_id;
On your model:
$id = $this->db->get('users')->where("name", "John")->id;
$rows = $this->db->get('users')->where("id < ", $id)->num_rows();
return $rows;
Notice how I'm using "chained methods" and for that you need PHP5 which is the default for CI 2.
You first need to get the ID of the record you need to start counting "backwards" which is the first line, considering a table called users and that the column you are filtering is "name" and the row you want to find has the name value of John.
The second line will give you the number of rows that the query "where id < number" returned where number is the ID you got from the first query. Maybe you can even chain both lines.

Categories