I have a table like so:
User_Id Column1 Column2 Column3
1 Yes No Yes
2
I want to use mysql query to list all the column names (there are more than 3) which match the User_Id '1' and have a value of 'Yes'.
I get an error:
Trying to get property 'num_rows' of non-object
Here is what I have tried:
<?php $myStats = $mysqli->query("SELECT COLUMN_NAME FROM user_services.columns WHERE myColumn = 'Yes'");
if ($myStats->num_rows > 0) {
// output data of each row
while($row = $myStats->fetch_assoc()) {
$rows[] = $row; }
return $rows; ?>
Please can someone show me where I am going wrong?
Thanks in advance.
The CONCAT_WS function comes in handy here:
SELECT CONCAT_WS(',', IF(Column1='Yes', 'Column1', NULL),
IF(Column2='Yes', 'Column2', NULL),
IF(Column3='Yes', 'Column3', NULL)) AS columns
FROM user_services.columns
WHERE User_Id = 1;
If you have more than 3 columns, then you may add more terms to above CONCAT_WS call. Your problem mainly seems to be a SQL one, so I won't add any PHP code.
Note that your design might be better off if your column strings were spread across rows, rather than columns. For instance, consider the following alternative:
User_Id | number | val
1 | 1 | Yes
1 | 2 | No
1 | 3 | Yes
Then, if you wanted all column numbers which were yes for user 1, you could simply do:
SELECT
User_Id,
GROUP_CONCAT(number ORDER BY number) columns
FROM yourTable
WHERE
User_Id = 1
GROUP BY
User_Id;
Related
$query = "SELECT COUNT(id) FROM complaint WHERE ID_complntCategory = ?";
$complntCategory = $database->prepare($query);
try {
$complntCategory->execute(array());
$complntCategory->setFetchMode(PDO::FETCH_ASSOC);
foreach ($complntCategory as $key) {
$totaalM = $key['1'];
$totaalV = $key['2'];
$totaalG = $key['3'];
}
}
catch(PDOException $e) {
echo "Error";
}
Above you see my PHP code, and here is what I'm trying to do:
I'm trying to get the amount of rows from the table 'complaint' into 3 different variables (totaalM, totaalV and totaalG). The totaalM variable should contain the amount of rows 'WHERE ID_complntCategory = 1'.
For the other variables the 'ID_complntCategory' should be 2 and 3
('ID_complntCategory' is either 1, 2 or 3)
There should be a way where I don't have to write 3 queries, right?
I'm clearly approaching this the wrong way, and I'm not sure how I should tackle this problem...
What you are trying to do is called pivot rows into columns, but MySQL doesn't have pivot table operator like other RDBMS, but you cane use the case expression like this in one query:
SELECT
SUM(CASE WHEN ID_complntCategory = 1 THEN 1 ELSE 0 END) AS totaalM,
SUM(CASE WHEN ID_complntCategory = 2 THEN 1 ELSE 0 END) AS totaalV,
SUM(CASE WHEN ID_complntCategory = 3 THEN 1 ELSE 0 END) AS totaalG,
COUNT(Id) AS Total
FROM complaint;
Or you can make it shorter like this:
SELECT
SUM(ID_complntCategory = 1) AS totaalM,
SUM(ID_complntCategory = 2) AS totaalV,
SUM(ID_complntCategory = 3) AS totaalG,
COUNT(Id) AS Total
FROM complaint;
Demo
This will give you something like this:
| totaalM | totaalV | totaalG | Total |
|---------|---------|---------|-------|
| 2 | 3 | 1 | 7 |
Here you need some magic, involving special SQL and PDO features.
First, you need an SQL query that is giving you desired results in one query. To get that you need a GROUP BY operator:
SELECT ID_complntCategory, count(*) FROM complaint GROUP BY ID_complntCategory
it will give you counts split by ID_complntCategory.
Next, you can use one of PDO's magnificent features, PDO::FETCH_KEY_PAIR fetch mode, that will give you an array where key would be category id and value is count
$sql = "SELECT ID_complntCategory, count(*) FROM complaint GROUP BY ID_complntCategory";
$stmt = $database->prepare($sql);
$key = $stmt->fetchAll(PDO::FETCH_KEY_PAIR);
$totaalM = $key['1'];
$totaalV = $key['2'];
$totaalG = $key['3'];
note that you should never catch a PDO errors only to say "error". Let PHP error reporting to do it instead.
I can't figure out how to get results from 2 tables, in 1 query result (can't simple JOIN)
I have these 2 tables in my MySQL database:
Table 1: sales
id
name
info
Table 2: users
sale_id
user_id
Now, every sale have different number of assigned users. Some sale have 2 users, some sale have 10 users.
In single row, I need to have columns from sale table, and all assigned users to it (connected with same Sale_id)
I need result, something like this:
enter image description here
Try this :
SELECT s.*,
(SELECT GROUP_CONCAT(u.user_id SEPARATOR ', ')
FROM users u
WHERE u.sale_id = s.id) AS users
FROM sales s
Some insight on your programming language would have been nice.
And yes, as suggested by wogsland and icoder, one typically use joins and loop through results to build en array. But the use of GROUP_CONCAT, as Yoleth pointed out, is what you need. I don’t know if it was the goal here, but it can reduce memory used in the result because there is no row repetition.
SELECT info FROM Sales AS s,
(
SELECT sale_id, GROUP_CONCAT(user_id) AS assigned_users
FROM Users
GROUP BY sale_id) AS u
WHERE s.id=u.sale_id;
In a single query, with a fancy JOIN:
SELECT s.info AS info, u.sale_id AS sale_id, GROUP_CONCAT(u.user_id) AS assigned_users
FROM Sales AS s LEFT JOIN Users AS u
ON s.id=u.sale_id
WHERE sale_id IS NOT NULL GROUP BY u.sale_id;
You can simply join two tables and get query result set like this:
saleID | saleName | userID | userName
1 | Oct Sale | 5 | Tim
1 | Oct Sale | 6 | Nik
2 | Nov Sale | 7 | Bill
Then you can walk each row and build associative array from that data:
$sales = array();
while( $row = mysqli_fetch_assoc($result)) {
if (!array_key_exists($row['saleID'], $sales)) {
$sales[$row['saleID']] = array(
'saleID' => $row['saleID'],
'saleName' => $row['saleName'],
'users' => array()
);
}
array_push($sales[$row['saleID']]['users'], array(
'userID' => $row['userID'],
'userName' => $row['userName']
));
}
Well, MySQL isn't going to return you a nice nested array like that. But you can create it by looping through the result. Assuming your MySQL connection is named $mysqli then try something like
$sales = array();
$result = $mysqli->query("SELECT sales.*, users.user_id FROM sales, users WHERE sales.id = users.sales_id");
while ($row = $result->fetch_assoc()) {
$sales[$row->id]['sales_id'] = $row->id;
$sales[$row->id]['name'] = $row->name;
$sales[$row->id]['info'] = $row->info;
$sales[$row->id]['assigned_users'][] = $row->user_id;
}
I need to sum the totals of a row except the first column.
Something similar too:
SELECT SUM( col2 + col3 + col4 +colN)
FROM numbers
WHERE user_name = 'person';
My table will continuously have columns added to it. So I want it to automatically pick up the sum of the new columns too without it needing to be hard coded into the query?
user_name | Col | col2 | Col3 | Col4 + other columns.
person1 | 2 | 3 | 76 | 56 etc. ---------> sum of row
person2 | 6 | 72 | 200 | 13 etc. ---------> sum of row
Thanks in advance for any help!
Not wishing to 'avoid' the question, but it looks like you could do with having a different data structure.
You should consider having a 'users' table with columns for id and user_name, and a new table (e.g. properties) with a row for each of the other columns in your current table (Col1, Col2 ... ColN). The new table would then have a column for user_name to link it to the users table.
That way you'd be able to do something like:
SELECT SUM(property_column) FROM properties WHERE user_name = <RequiredUserName>
I'd also recommend selecting users by ID (i.e. have the properties table with a user_id column, rather than a user_name column), unless you're confident that a user_name is never going to change (and even then...).
Maybe the easiest solution is to do it in PHP:
$res = mysql_query("select * from numbers where user = ...");
while ($row = mysql_fetch_assoc($res)) {
$row['Id'] = 0; // don't want to sum the Id
$sum = array_sum($row); // this is the required sum
....
}
As stated you would be better advised revisiting your database structure,
If you can't and
If you want to do it in PHP you can get the resultset back and then loop through the fields and exclude the fields you don't want then add up everything else, assuming it is of the right type, use mysql_field_type to find those of a specific type.
I have around 30 columns in a MySQL table. I want to calculate how many column fields for a particular row are empty. This table is for storing user information. I want to find out how many profile fields (such as 'Name', 'Age', 'Location' - all of which are stored in a separate column) are empty/haven't been filled in by the user.
The columns I want to refine down are the final 20 columns (because the first 10 columns store stuff like User IDs, passwords, etc. - I only want the final 20 columns which store profile information). How do I find out the AMOUNT of empty/NULL columns in this table?
If the idea is to get a result something like this:
col emp
------ ------
FName 15
LName 2
Age 22
..use:
SELECT 'FName' AS col, SUM(CASE FName IS NULL || FName='' THEN 1 ELSE 0 END) as emp FROM MyTable
UNION
SELECT 'LName' AS col, SUM(CASE LName IS NULL || LName='' THEN 1 ELSE 0 END) as emp FROM MyTable
UNION
SELECT 'Age' AS col, SUM(CASE Age IS NULL || Age='' THEN 1 ELSE 0 END) as emp FROM MyTable
...or:
SELECT SUM(CASE t.fname IS NULL OR t.fname = '' THEN 1 ELSE 0 END) AS fname_count,
SUM(CASE t.lname IS NULL OR t.lname = '' THEN 1 ELSE 0 END) AS lname_count,
SUM(CASE t.age IS NULL OR t.age = '' THEN 1 ELSE 0 END) AS age_count
FROM MYTABLE t
You can compute it like this:
SELECT SUM((`Name` = '') + (`Age` = 0) + (`Location` = '' OR `Location` IS NULL) + ...)
You didn't specify what types of columns you have so I used different comparing methods to illustrate the point. As a general idea you should compare to see if a specific column value is equal to the default value for that field (i.e. field not specified by the user). Use = '' for strings, = 0 for numbers, IS NULL for columns that have default NULL etc. You could also combine checks for NULL and empty value if you want. It all depends on what you want to find out.
Of course, as dnagirl pointed out in her answer, you should test for both empty and NULL values, but that really depends on how your columns are defined and also if you consider empty values to be filled or not. The point I was trying to make is that you can use SUM to add up boolean expression results.
EDIT: Didn't notice that you wanted for each row. Just remove the SUM and you'll get it per row.
As I understand it you have a table such as
id | FName | LName | Age
1 | John | "" | NULL
2 | Mary | Simons | NULL
And you want: row 1 has 2 empty/null fields, and row 2 has 1 empty/null fields
SELECT
id,
IF (FName IS NULL OR FName = '', 1, 0) +
IF (LName IS NULL OR LName = '', 1, 0) +
IF (Age IS NULL OR Age = '', 1, 0)
as empty_field_count
Though now that I've written this I see Saul's response, I think that may have better performance that this solution.
In addition to what #dnagirl answered, I would consider doing an extra step... adding a column to the table for "anyNulls". And set it as a flag for ANY empty/null values, so you would be able to quickly query those that need to be completed for data requirements instead of just how many of each category. One record could have all fields missing vs one column in multiple rows that need to be fixed.
I'm using MySQL with PHP. This is like my table: (I'm using 3 values, but there are more)
id | 1 | 2 | 3
---+---+---+----
1 | 3 |12 |-29
2 | 5 |8 |8
3 | 99|7 |NULL
I need to get the greatest value's column name in a certain row. It should get:
id | maxcol
---+-------
1 | 2
2 | 2
3 | 1
Are there any queries that will do this? I've been trying, but I can't get it to work right.
Are you looking for something like the GREATEST function? For example:
SELECT id, GREATEST(col1, col2, col3)
FROM tbl
WHERE ...
Combine it with a CASE statement to get column names:
SELECT id, CASE GREATEST(COALESCE(`1`, -2147483646), COALESCE(`2`, -2147483646), COALESCE(`3`, -2147483646))
WHEN `1` THEN 1
WHEN `2` THEN 2
WHEN `3` THEN 3
ELSE 0
END AS maxcol
FROM tbl
WHERE ...
It's not pretty. You'd do better to follow Bill Karwin's suggestion and normalize, or simply take care of this in PHP.
function findcol($cmp, $arr, $cols=Null) {
if (is_null($cols)) {
$cols = array_keys($arr);
}
$name = array_shift($cols);
foreach ($cols as $col) {
if (call_user_func($cmp, $arr[$name], $arr[$col])) {
$name = $col;
}
}
return $name;
}
function maxcol($arr, $cols=Null) {
return findcol(create_function('$a, $b', 'return $a < $b;'), $arr, $cols);
}
This is a great example of the way normalization helps make query design easier. In First Normal Form, you would create another table so all the values would be in one column, on separate rows.
Since you have used repeating groups to store your values across three columns, you can find the column with the greatest value this way:
SELECT id, IF(col1>col2 AND col1>col3, 'col1', IF(col2>col3, 'col2', 'col3'))
AS column_with_greatest_value
FROM mytable;
The short answer is that there is no simple means to do this via a query. You would need to transpose your data and then determine the largest value that way. So something like:
Select Id, ColumnName, Value
From (
Select '1' As ColumnName, Id, [1] As Value
From Table
Union All
Select '2', Id, [2]
From Table
Union All
Select '3', Id, [3]
From Table
) As Z
Where Exists(
Select 1
From (
Select '1' As ColumnName, Id, [1] As Value
From Table
Union All
Select '2', Id, [2]
From Table
Union All
Select '3', Id, [3]
From Table
) As Z2
Where Z2.Id = Z.Id
Group By Z2.Id
Having Max(Z2.Value) = Z.Value
)
Order By Id
This solution depends on a fixed set of columns where you basically name the columns in the UNION ALL queries. In addition, if you have two columns with identical values for the same Id, you will get duplicate rows.
This query will return the max value regardless of NULLs
SELECT MAX(value)
FROM
(SELECT 1 column_no, col1 value
FROM anotherunamedtable
UNION ALL
SELECT 2, col2
FROM anotherunamedtable
UNION ALL
SELECT 3, col3
FROM anotherunamedtable) t
If you really need the column number then
SELECT id,
(SELECT column_no
FROM
(SELECT 1 column_no, col1 value
FROM anotherunamedtable
WHERE id = t.id
UNION ALL
SELECT 2, col2
FROM anotherunamedtable
WHERE id = t.id
UNION ALL
SELECT 3, col3
FROM anotherunamedtable
WHERE id = t.id) s
ORDER BY max_value DESC
LIMIT 1)) as column_no
FROM anotherunamedtable t
But I think that the last query might perform exceptionally horrible.
(Queries are untested)
In the php side, you could do something like this:
foreach ($rows as $key => $row) {
$bestCol = $best = -99999;
foreach ($row as $col => $value) {
if ($col == 'id') continue; // skip ID column
if ($value > $best) {
$bestcol = $col;
$best = $value;
}
}
$rows[$key]['best'] = $bestCol;
}
Or something similar...
Forests and trees, here's a trivial and fastest solution (providing I didn't fumble); the expression simply looks for the largest column in the row
SELECT id,
CASE COALESCE(col1, -2147483648) >= COALESCE(col2, -2147483648)
WHEN
CASE COALESCE(col2, -2147483648) >= COALESCE(col3, -2147483648)
WHEN true THEN 1
ELSE
CASE COALESCE(col1, -2147483648) >= COALESCE(col3, -2147483648)
WHEN true THEN 1
ELSE 3
END
END
ELSE
CASE COALESCE(col2, -2147483648) >= COALESCE(col3, -2147483648)
WHEN true 2
ELSE 3
END
END
FROM table t
a version with IF() would maybe be more readable, but the above should perform a bit better
To deal with NULLS an INT value with minimum of -2147483648 was assumed, the expression could be rewritten to deal explicitly with nulls but would have to branch into 8 different cases and is left as an exercise for the OP.