How can i get the total of a column in mysql? - php

Alright, I am kind of new to SQL and I have no idea on how I am going to do this. I have tried to google but maybe I'm not sure if I am searching for the right question. So here it is. I have 2 tables in my database. One is called events and another one is called eventtypes.
My eventtype table looks like this..
-------------------
eventID | eventName|
1 | eveA |
2 | eveB |
3 | eveC |
___________________
and my events table, looks like this
--------------------------
eventCat |UserRegistered |
1 | John |
2 | Mac |
3 | Assz |
2 | Ez |
3 | Pz |
_________________________
(I hope you understand my table.....)
events.eventCat=eventtype.eventID
Now, what I am trying to do is to, calculate the numbers of participants for event 1, 2 and 3 in events table and later display the number of users who will be attending appropriately by using the eventtype table using php.
Can somebody help me out with this ? Thanks a bunch !

create table eventtype
( eventID int not null,
eventName varchar(100) not null
);
insert eventtype(eventID,eventName) values
(1,'eveA'),
(2,'eveB'),
(3,'eveC');
create table events
( eventCat int not null,
UserRegistered varchar(100) not null
);
insert events(eventCat,UserRegistered) values
(1,'John'),
(2,'Mac'),
(3,'Assz'),
(2,'Ez'),
(3,'Pz');
Query:
select e.eventId,count(u.UserRegistered) as theCount
from eventtype e
join events u
on u.eventCat=e.eventId
group by e.eventId
order by e.eventId;
+---------+----------+
| eventId | theCount |
+---------+----------+
| 1 | 1 |
| 2 | 2 |
| 3 | 2 |
+---------+----------+

You can apply join and group by to acheive this -
SELECT count(UserRegistered),eventName from events join eventtype on
events.eventCat=eventtype.eventID
GROUP BY eventCat
Hope this will help you.

The followng query should work.it will select the no of participants based on the event using group by clause
SELECT count(UserRegistered),eventName
From events,eventype
WHERE events.eventCat=eventtype.eventID
GROUP BY eventCat

Related

How SELECT separate | column mysql php (1|0|2|1|0|0|1)

I have column student_hobbys in my mysql table:
student_hobbys
1|0|1|1|0|0|1|0
now i try search all students who likes geography (school subject). In column student_hobbys i save this value in second argument (1|here|0|1|...). How to create a mysql query that will select students who like geography?
please help
Please read here why your design is a bad idea. You should store you data in a normalized way as follows:
table studens:
id | name
1 | John
2 | Jane
3 | Mike
4 | Spike
table hobbies:
id | name
1 | biology
2 | geogryphy
3 | football
4 | programming
table students_hobbies:
student_id | hobby_id
1 | 3
1 | 4
2 | 1
2 | 2
3 | 1
3 | 2
3 | 4
4 | 3
Schema definition:
CREATE TABLE students (
id INT UNSIGNED AUTO_INCREMENT,
name VARCHAR(50),
PRIMARY KEY (id),
INDEX (name)
);
CREATE TABLE hobbies (
id INT UNSIGNED AUTO_INCREMENT,
name VARCHAR(50),
PRIMARY KEY (id),
INDEX (name)
);
CREATE TABLE students_hobbies (
student_id INT UNSIGNED,
hobby_id INT UNSIGNED,
PRIMARY KEY (student_id, hobby_id),
INDEX (hobby_id, student_id)
);
And your SELECT query now would be:
SELECT s.*
FROM students s
JOIN students_hobbies sh ON sh.student_id = s.id
JOIN hobbies h ON h.id = sh.hobby_id
WHERE h.name = 'geogryphy';
Result:
| id | name |
| --- | ---- |
| 2 | Jane |
| 3 | Mike |
View on DB Fiddle
However - If you want to stick with your design, you can try something like this:
SELECT *
FROM students
WHERE student_hobbys LIKE '_|1%'
View on DB Fiddle
But it would be quite complex to generate this query programmatically. It will probably also be slower than the above solution on big dada sets, because there is no way to use an index for this kind of query.
If you want to avoid complex code in your application, you will need a quite more comlex query. One way would be to convert your string to a bitmask, and then use the bit operator & to check the bit at a specific position:
SET #hobby_position = 2;
SELECT *
FROM students
WHERE CONV(REVERSE(REPLACE(student_hobbys, '|', '')), 2, 10) & 1 << (#hobby_position - 1);
| id | name | student_hobbys |
| --- | ---- | --------------- |
| 2 | Jane | 1|1|1|1|0|0|1|0 |
| 3 | Mike | 1|1|1|1|0|0|1|0 |
View on DB Fiddle
There are other ways - But you will unlikely find a simple one, which can work with your design.

MySQL and PHP One to Many Return Data in Single Row, Multiple Columns

I have been learning PHP and MySQL for a project and I am struggling with this part. For simplicity sake, I will only list the relevant fields (actually many more in real db) let's say I have 3 tables.
Table1
---------------------
Index | Name | email
1 | Rob | rob#email.com
2 | Kevin| kevin#email.com
3 | Amy | amy#email.com
Table2
------------------------
id | Info | Submitted
1 | Blah | 0
2 | Yada | 1
Table 3
-------------------------
id | Goal |Submitted
1 | 1 | 1
1 | 2 | 1
1 | 3 | 1
1 | 4 | 0
1 | 5 | 0
3 | 1 | 0
3 | 3 | 1
3 | 4 | 1
So, Table1 holds user information and is kinda the main table
Table2 the user inputs some data in a field and then submits for approval when ready. (I will be using the value of Submitted for functions later)
If the user has not submitted the info, there is not record. This is a 1 to 1 with Table1
Table3 The user inputs information for 5 goals. At any given time there could be 0 to max 5 goals entered for a user. The Submitted is the same for later processing. This table is Many to one with Table1. The Goal field literally shows the number 1 through 5, there is a separate field that holds the goal text, just not needed in this example.
Desired output is HTML table
Name | email | info |Goal1|Goal2|Goal3|Goal4|Goal5|
Rob | rob#email.com | Blah | 1 | 2 | 3 | 4 | 5 |
Kevin | kevin#email.com | Yada | | | | | |
Amy | amy#email.com | | 1 | | 3 | 4 | |
Not sure if the blanks are considered NULL or something else as they do not exist in the DB. I would like to put something in the field like an *. Basically the Submitted will be used for code to make the fields hyper links, so they need to be part of the query, just not in the table display, but if it would help, it can be displayed.
Name | email | info |Goal1|Goal2|Goal3|Goal4|Goal5|
Rob | rob#email.com | Blah | 1 | 2 | 3 | 4 | 5 |
Kevin | kevin#email.com | Yada | * | * | * | * | * |
Amy | amy#email.com | * | 1 | * | 3 | 4 | * |
I am using a query with left joins and group_concat, but that is not working well with the non existent data, and I cannot figure out how to include the Submitted field without doing some crazy concatenation, then pulling in all apart to put in the HTML fields.
I can include some code, but it might be hard to follow as there are lots of variables being used.
The best I have gotten out using only table1 and table3:
Rob 1,2,3,4,5
Kevin
Amy 1,3,4
With the records that have not been entered not be accounted for, it makes it near impossible to turn the data string into a table. If I can get something showing for every position, even if it does not exist yet, I do know how to make it into the html table.
I hope this makes sense and someone can help me with this.
As you stated that you have at most 5 goals. The best possible option is to use following query.
SELECT t1.Name,t1.email
,CASE WHEN t2.Info IS NULL THEN * ELSE t2.Info END as Info
,CASE WHEN g1.Goal IS NULL THEN * ELSE g1.Goal END as Goal1
,CASE WHEN g2.Goal IS NULL THEN * ELSE g2.Goal END as Goal2
,CASE WHEN g3.Goal IS NULL THEN * ELSE g3.Goal END as Goal3
,CASE WHEN g4.Goal IS NULL THEN * ELSE g4.Goal END as Goal4
,CASE WHEN g5.Goal IS NULL THEN * ELSE g5.Goal END as Goal5
FROM Table1 as t1
LEFT JOIN Table2 as t2 ON t2.id = t1.Index
LEFT JOIN Table3 as g1 ON g1.id = t1.Index AND g1.Goal=1
LEFT JOIN Table3 as g2 ON g2.id = t1.Index AND g2.Goal=2
LEFT JOIN Table3 as g3 ON g3.id = t1.Index AND g3.Goal=3
LEFT JOIN Table3 as g4 ON g4.id = t1.Index AND g4.Goal=4
LEFT JOIN Table3 as g5 ON g5.id = t1.Index AND g5.Goal=5
You will want to JOIN each of the tables together, and GROUP BY the user.
One way of handling the goals would be to display it as one column, containing all goals.
This should help you get started:
SELECT name,
email,
info,
<LOGIC> as goals
FROM table1
JOIN table2 ON table2.user_id = table1.id
JOIN table3 ON table3.user_id = table1.id
GROUP BY name
The logic that you use for the goals column could be created with a mixture of CASE and CONCAT (if a goal is defined, concatenate it into a string, and display that string as the final value of goals).

MySQL populating field based on another table using LIKE match

I know it's not the cleanest code to date, but I can't figure out why I can't get this one to work.
I'm looking to populate the field m.customersTemp with Customer Numbers from field c.ClientNumber. But only when a LIKE match from c.EmailAddress is found m.Emails... m.Emails is a field with a list of e-mails. Code Below.
UPDATE market m, customer c
SET m.customersTemp = CONCAT(m.customersTemp, c.ClientNumber)
WHERE m.Emails LIKE CONCAT('%', TRIM(c.EMailAddress), '%')
AND TRIM(c.EMailAddress)<>''
The result in field m.customersTemp only displays one value (customer number)... and I know there are many matches.
TABLE CUSTOMER
ClientNumber | EMailAddress
1234 a#a.com
4567 b#b.com
2222
1111 d#d.com
-------------------------------------------------------------
| TABLE MARKET |
-------------------------------------------------------------
| ID | Emails | customersTemp|
-------------------------------------------------------------
|1 | a#a.com, b#b.com, c#c.com | |
|2 | a#a.com, b#b.com, g#g.com | |
|3 | e#e.com | |
|4 | f#f.com | |
-------------------------------------------------------------
Result in customersTemp at ID 1 and 2 is only 1 ClientNumber. 4567
Don't forget to read the Warning at the bottom as to why you should NEVER save your data like this.
You can test this on a backup copy. I wouldn't run it against your main tables. Akin to someone saying: "Here, try this delete command, I think it will work."
-- drop table customer;
create table customer
( ClientNumber int,
EMailAddress varchar(100)
);
insert customer (ClientNumber,EMailAddress) values
(1234,'john#john.com'),
(4567,'joe#joe.com'),
(2222,''),
(1111,'somone#someone.com'),
(5454,'john#john.com');
-- drop table market;
create table market
( Emails varchar(100),
customersTemp varchar(100)
);
insert market(Emails,customersTemp) values
('john#john.com',''),
('joe#joe.com',''),
('test#test.com',''),
('more#more.com','');
The Update statement:
UPDATE market
INNER JOIN
( SELECT c.EMailAddress as e,GROUP_CONCAT(c.ClientNumber ORDER BY c.ClientNumber) theList
FROM customer c
GROUP BY c.EMailAddress
) xDerived1
ON market.EMails = xDerived1.e
SET market.customersTemp = xDerived1.theList;
Results:
select * from market;
+---------------+---------------+
| Emails | customersTemp |
+---------------+---------------+
| john#john.com | 1234,5454 |
| joe#joe.com | 4567 |
| test#test.com | |
| more#more.com | |
+---------------+---------------+
Version2
drop table customer;
create table customer
( ClientNumber int,
EMailAddress varchar(100)
);
insert customer (ClientNumber,EMailAddress) values
(1234,'a#a.com'),
(4567,'b#b.com'),
(2222,''),
(1111,'d#d.com'),
(8484,'g#g.com');
-- select * from customer;
drop table market;
create table market
( id int auto_increment primary key,
Emails varchar(100),
customersTemp varchar(3000)
);
insert market(Emails,customersTemp) values
('a#a.com,b#b.com,c#c.com',''),
('a#a.com,b#b.com,g#g.com',''),
('e#e.com',''),
('f#f.com','');
-- select * from market;
drop table if exists marketHelper7;
create table marketHelper7
( -- btw this might be the kind of table
-- as an intersect/junction table that you
-- should have to begin with
-- and not have your CSV stuff
cid int not null,
mid int not null
);
insert marketHelper7 (cid,mid)
select c.ClientNumber,m.id as MarketId
from customer c
join market m
on find_in_set(c.EMailAddress,m.Emails)>0;
update market set customersTemp=''; -- do a reset
UPDATE market m
join
( SELECT mh.mid as i,GROUP_CONCAT(mh.cid ORDER BY mh.cid) theList
FROM marketHelper7 mh
GROUP BY mh.mid
) xDerived1
ON m.id = xDerived1.i
SET m.customersTemp = xDerived1.theList;
drop table marketHelper7;
.
select * from market;
+----+-------------------------+----------------+
| id | Emails | customersTemp |
+----+-------------------------+----------------+
| 1 | a#a.com,b#b.com,c#c.com | 1234,4567 |
| 2 | a#a.com,b#b.com,g#g.com | 1234,4567,8484 |
| 3 | e#e.com | |
| 4 | f#f.com | |
+----+-------------------------+----------------+
Version 2 above has the helper table.
Warning:
By the way, never save your data like this. It is insane, and the performance is awful. Please see my answer here on Junction Tables (many-to-many) (similar to association tables or "item has" tables a.k.a. One-to-Many). They are all the same concept that utilized Data Normalization best practices and fast indexes during queries. Plus you stay happier not fighting with your data constantly or wondering if you blow the buffer size with group_concat.
Note that group_concat() has flexibility for its separator choice, and the order by, baked inside the function call.
The maximum length for the output of group_concat is subject to the system variable group_concat_max_len which probably defaults to 1K but can be set to at least 4GB.
The Percona article on group_concat(), and the manual pages for group_concat() and find_in_set().

MySQL struggling with a query to find similar details among products

I have a query to write and I am absolutely stumped on how to do it. Here's my situation, I am trying to provide a particular product_ID, then match all of the other product_IDs in the database that have at least the same intDescription_detail_IDs as the provided product_ID.
The relevant tables look like this:
tblproducts
=========================
product_ID | product_name
=========================
| 1 | dresser |
| 2 | bookcase |
| 3 | table |
| 4 | chair |
=========================
tbldescriptions
=========================================================================
|description_ID| intDescription_product_ID | intDescription_detail_ID |
=========================================================================
| 1 | 1 | 1 |
| 2 | 1 | 2 |
| 4 | 2 | 1 |
| 5 | 2 | 2 |
| 6 | 2 | 6 |
| 7 | 3 | 1 |
| 8 | 3 | 3 |
| 9 | 3 | 4 |
| 10 | 4 | 1 |
| 11 | 4 | 2 |
| 12 | 4 | 7 |
As an example, if I provided the product_ID "1", then I would like to return all of the product_IDs that at least have intDescription_detail_ID 1 and 2.
So, the product_IDs that should be returned are 1, 2, and 4, because all of these products have the intDescription_detail_ID of 1 and 2 among their details.
I am highly confused about how to write a query like this, so any help is greatly appreciated!
I should warn you by saying that I may have made a silly mistake here...
DROP TABLE IF EXISTS products;
CREATE TABLE products(product_ID INT NOT NULL AUTO_INCREMENT PRIMARY KEY,product_name VARCHAR(20) NOT NULL UNIQUE);
INSERT INTO products VALUES
(1,'dresser'),
(2,'bookcase'),
(3,'table'),
(4,'chair');
DROP TABLE IF EXISTS product_detail;
CREATE TABLE product_detail
(product_id INT NOT NULL
,detail_id INT NOT NULL
,PRIMARY KEY(product_id,detail_id)
);
INSERT INTO product_detail VALUES
(1,1),
(1,2),
(2,1),
(2,2),
(2,6),
(3,1),
(3,3),
(3,4),
(4,1),
(4,2),
(4,7);
SELECT DISTINCT c.product_id
FROM product_detail a
JOIN product_detail b
ON b.product_id = a.product_id
AND b.detail_id <> a.detail_id
JOIN product_detail c
ON c.product_id <> a.product_id
AND c.detail_id = a.detail_id
JOIN product_detail d
ON d.product_id = c.product_id
AND d.detail_id = b.detail_id
WHERE a.product_id = 1;
+------------+
| product_id |
+------------+
| 2 |
| 4 |
+------------+
Alternative to #Strawberry’s suggestion with JOINs this can also be done using HAVING for filtering products that have (at least) the same number of rows with the same intDescription_detail_IDs as the product the search is done for:
SELECT intDescription_product_ID
FROM tbldescriptions t1
WHERE intDescription_detail_ID IN (
SELECT intDescription_detail_ID
FROM tbldescriptions t2
WHERE t2.intDescription_product_ID = 1
)
GROUP BY intDescription_product_ID
HAVING count(*) >= (
SELECT count(intDescription_detail_ID)
FROM tbldescriptions t3
WHERE t3.intDescription_product_ID = 1
)
http://sqlfiddle.com/#!2/ce698/2
One should keep in mind though that HAVING is applied last, so that will select all products with at least one matching intDescription_detail_ID first, and filter the results based on the actual count afterwards – so depending on the size and characteristic of your data set that might not be the best performing solution.

GROUP_CONCAT With Nested Set Model

I have an application that uses a nested set model class to organise my data, however I'm trying to write a query that will group_concat my results. I know I need to put some sub select statements somewhere but I can't figure it out!
Here's my structure at the moment:
table: person
-----------+------------+-----------
|Person_ID | Name | Age |
-----------+------------+-----------
| 1 | Mark Vance | 19 |
| 2 | Michael Tsu| 22 |
| 3 | Mark Jones | 29 |
| 4 | Sara Young | 25 |
-----------+------------+-----------
table: person_to_group
----+------------+-----------
|ID | Person_ID | Group_ID |
----+------------+-----------
| 1 | 3 | 1 |
| 2 | 3 | 2 |
| 3 | 1 | 2 |
| 4 | 4 | 3 |
----+------------+-----------
table: groups
----------+--------------+--------------+-------------
|Group_ID | Group_Name | Group_Left | Group_Right |
----------+--------------+--------------+-------------
| 1 | Root | 1 | 6 |
| 2 | Node | 2 | 5 |
| 3 | Sub Node | 3 | 4 |
----------+--------------+--------------+-------------
I need to render something like this with my results:
//Grab the group_IDs for this person and put them in the class tag...
<li class="2 3">Sara Young is in the Sub Node Group</li>
Notice that although Sara is in the Sub Node group, she is still being given the id for Node aswell because she is a child of Node.
The following is the query that I am working with as a starting point.
SELECT *, GROUP_CONCAT( CAST( gg.Group_ID AS CHAR ) SEPARATOR ' ' ) Group_IDs
FROM groups gg
LEFT JOIN person_to_group AS t1 ON gg.Group_ID = t1.Group_ID
LEFT JOIN person AS t2 ON t2.Person_ID = t1.Person_ID
GROUP BY t2.per_ID
ORDER BY t2.Name ASC
Any help would be much appreciated!
Here's how I'd write the query:
SELECT p.Name,
GROUP_CONCAT( g.Group_Name ) AS Group_List,
GROUP_CONCAT( CAST( gg.Group_ID AS CHAR ) SEPARATOR ' ' ) AS Group_ID_List
FROM person AS p
INNER JOIN person_to_group AS pg ON p.Person_ID = pg.Person_ID
INNER JOIN groups AS g ON pg.Group_ID = g.Group_ID
INNER JOIN groups AS gg ON g.Group_Left BETWEEN gg.Group_Left AND gg.Group_Right
GROUP BY p.Name
ORDER BY p.Name ASC
Note that if you group by person name, you also need to GROUP_CONCAT the list of group names. According to your schema, a person could belong to multiple groups, because of the many-to-many relationship.
I also recommend against using SELECT * in general. Just specify the columns you need.
This was little bit interesting as I do programming in both MsSQL and MySql. In SQL I have used function called STUFF. In MySQL you can use a function called INSERT. I tried out the below query in MsSQL. Don't have a MySQL handy to try out my query. If I have time I will post the MySQL version of the query.
DECLARE #person TABLE (Person_ID INT, Name VARCHAR(50), Age INT)
INSERT INTO #person VALUES
(1,'Mark Vance',19),
(2,'Michael Tsu',22),
(3,'Mark Jones',29),
(4,'Sara Young',25)
DECLARE #groups TABLE (Group_ID INT, Group_Name VARCHAR(50), Group_Left INT, Group_Right INT)
INSERT INTO #groups VALUES
(1,'Root',1,6),
(2,'Node',2,5),
(3,'Sub Node',3,4)
DECLARE #person_to_group TABLE (ID INT, Person_ID INT, Group_ID INT)
INSERT INTO #person_to_group VALUES
(1,3,1),
(2,3,2),
(3,1,1),
(4,4,1),
(4,1,1)
SELECT *,STUFF((SELECT ',' + CAST(g.Group_ID AS VARCHAR) FROM #groups g
JOIN #person_to_group pg ON g.Group_ID = pg.Group_ID AND pg.Person_ID = a.Person_ID FOR XML PATH('')) , 1, 1, '' ) FROM #person a
Function: INSERT(str,pos,len,newstr)
Documentation: http://dev.mysql.com/doc/refman/5.0/en/string-functions.html#function_insert

Categories