I am working on a php project for managing employees.
i have two tables employee and department with the department number being a relation between the two. department has an attribute that contains a count of employees based on the deparment number.
So where i'm stuck is that i want the employee count to be automatically inserted, so what do you think i should do
Thanks in advance
If you don't want to use (or have access to) a trigger, but want to abstract the logic, you could use a view (docs).
So assuming the below data, and the idea of having the entire department table and the employee count dynamically calculated, you could have the following query:
CREATE TABLE
`employees`
(
`employeeID` INT PRIMARY KEY AUTO_INCREMENT,
`name` VARCHAR(50),
`department_number` INT
);
CREATE TABLE
`departments`
(
`department_number` INT PRIMARY KEY AUTO_INCREMENT,
`name` VARCHAR(50)
);
INSERT INTO
`departments`
(`department_number`, `name`)
VALUES
(1, 'Tech Department'),
(2, 'Admin Department');
INSERT INTO
`employees`
(`name`, `department_number`)
VALUES
('John Doe', 1),
('Jane Doe', 1),
('Jimmy Doe', 2);
Then the query:
SELECT
DepartmentTbl.*,
DepartmentEmployeeTbl.employee_count
FROM
`departments` AS DepartmentTbl
LEFT JOIN
(
SELECT
`department_number`,
COUNT(`employeeID`) AS `employee_count`
FROM
`employees`
GROUP BY
`department_number`
) AS DepartmentEmployeeTbl
ON DepartmentTbl.department_number = DepartmentEmployeeTbl.department_number
Gives the result:
department_number | name | employee_count
-------------------------------------------------------
1 | Tech Department | 2
2 | Admin Department | 1
SQLFiddle - http://sqlfiddle.com/#!9/3e0b54/1
So to create this view, you could use:
CREATE OR REPLACE VIEW `departments_employee_count` AS
SELECT
DepartmentTbl.*,
DepartmentEmployeeTbl.employee_count
FROM
`departments` AS DepartmentTbl
LEFT JOIN
(
SELECT
`department_number`,
COUNT(`employeeID`) AS `employee_count`
FROM
`employees`
GROUP BY
`department_number`
) AS DepartmentEmployeeTbl
ON DepartmentTbl.department_number = DepartmentEmployeeTbl.department_number
Then you could call the view as:
SELECT
*
FROM
`departments_employee_count`
Instead of storing and updating the value each time something is changed you should just calculate it when needed.
You can use count to do it.
Example
SELECT department_number, count(*) FROM employee GROUP BY department_number
Related
quite a few hours struggling with a problem, it's more about the issue.
Depicting the script when you type in textboxa searches in SQL data records where name = contain. Assuming that I entered 2 names separated by a comma (X, Y) 2:
a) If you choose "all containing typed values" is to look for all the records, in the above "name". It works:
$where. = "AND name IN ('". implode (' ', ' ', $array). "')";
Model: Contains X.
Contains The Y;
Contains the Y and X;
It works as it should.
(b)) If you choose "all containing only the values to be entered to look for records in which only occurs in the" name "is what we have.
Here I do not know how to do it.
Model: contains the X and Y-only, I don't want records that contain only X, but Y and Alternatively, if in MySQL "name" is 3 options (X, Y, Z).
I do not know how to explain more clearly:--------------------example: I have 5 values in the table, where the name is in different combinations:
1) Name1, Name2,
2) name1, Name8,
3) name1, Name9,
4) Name8, Name3,
5) Name4, Name5,
using the selected the first option, where the textbox typed: "Name1, Name" the result will be: 1), 2), 3), 4), this is valid.
Using the second result should only be 2).
The result of a) res1 or res2 or res1 and res2.
Now I need somehow to come to a solution, when I type in textbox "res1, res2" the result will be: only the records that contain res1 and res2, and NOTHING AFTER that.
---- EDIT FOR REPLIES:
+--------------------- my_val_search -----------+
| aid | int(11) | primary key auto_increment|
|name | varchar(255)| |
+-----------------------------------------------+
Records:
1|Ruby
2|CSS
3|HTML
4|PHP
5|Python
6|SQL
7|Javascript
8|C++
9|AJAX
10|Java
+---------------------- topics -----------------+
|id | int(11) | Primary key auto_increment |
|dateline| date | |
|author | varchar(30) | |
|message | text | |
|aid |int(11) |foreign key with my_val_search|
+-----------------------------------------------+
Now if you type in the search "Ruby, Python" I want to have found records only for topics where are "Ruby and Python".
By using the
$myValInput = $_GET['keywords'];
$where = "AND a.name IN('" . implode("','", $myValInput. "')";
Searches for records, where when you type "Python, Ruby" is divided into:
-Python
-Ruby,
- Python and Ruby
and I want to make the results appear only for "Python and Ruby". In addition, if someone types "Python, Ruby, Java," the result should be
-Python, Ruby, Java,
the record should be just what I wrote, nothing more.
Using IN cannot get what you expect!
When used with a subquery, the word IN is an alias for = ANY. Thus, these two statements are the same:
SELECT s1 FROM t1 WHERE s1 = ANY (SELECT s1 FROM t2);
SELECT s1 FROM t1 WHERE s1 IN (SELECT s1 FROM t2);
https://dev.mysql.com/doc/refman/5.7/en/any-in-some-subqueries.html
Besides, I think your schema is incorrect. The topic should be parent and the topic keywords should be child. If I were you, I will do it like this.
CREATE TABLE IF NOT EXISTS `topic` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`dateline` date,
`author` varchar(30),
`message` text,
PRIMARY KEY(`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1;
CREATE TABLE IF NOT EXISTS `topic_keywords` (
`topic` int(10) unsigned NOT NULL,
`keyword` varchar(255),
FOREIGN KEY (`topic`) REFERENCES `topic` (`id`),
UNIQUE INDEX (`topic`, `keyword`)
) ENGINE=InnoDB;
In your case, I think the full text is suitable.
https://dev.mysql.com/doc/refman/5.7/en/fulltext-boolean.html
CREATE TABLE IF NOT EXISTS `topic` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`dateline` date,
`author` varchar(30),
`message` text,
`keywords` varchar(255),
PRIMARY KEY(`id`),
FULLTEXT (`keywords`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1;
INSERT INTO `topic` (`keywords`)
VALUES ('Ruby,Python'),
('Ruby'),
('Ruby,SQL'),
('Python'),
('Python,SQL'),
('Ruby,Python,SQL,AJAX');
SELECT `keywords`
FROM `topic`
WHERE MATCH(`keywords`) AGAINST('+Ruby +Python' IN BOOLEAN MODE);
+----------------------+
| keywords |
+----------------------+
| Ruby,Python |
| Ruby,Python,SQL,AJAX |
+----------------------+
2 rows in set (0.00 sec)
If you just find out the records just exact your input. You can add a hash column. Like design a hash table for your Mysql table. So you can use hash value in your query statement. But don't forget to update the hash value, if your keywords value had been changed. Add the before update trigger might be a good choice.
CREATE TABLE IF NOT EXISTS `topic` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`dateline` date,
`author` varchar(30),
`message` text,
`keywords` varchar(255),
`keywords_hash` varchar(32),
PRIMARY KEY(`id`),
FULLTEXT (`keywords`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1;
INSERT INTO `topic`
(`keywords` , `keywords_hash`)
VALUES ('Ruby,Python', md5('Ruby,Python'));
SELECT `keywords`
FROM `topic`
WHERE `keywords_hash` = md5('Ruby,Python');
Here's an attempt at a solution, but there's better solutions query wise than using a regular denormalized structure to handle this - so if you're going to query this a lot (and with a large number of terms), you might want to look into caching the lookup values in your original table and then querying by their content. Anyway, to solve it with regular joins:
Given data:
CREATE TABLE foo (id int);
CREATE TABLE foo_bar (foo_id int, bar_id int);
CREATE TABLE bar (id int, name varchar(25));
INSERT INTO foo VALUES (1), (2), (3), (4);
INSERT INTO bar VALUES (1, 'Ruby'), (2, 'Python'), (3, 'PHP');
INSERT INTO foo_bar VALUES (1, 1), (2, 1), (3, 3), (4, 3), (2,2);
You can retrieve id values from foo that has both Ruby and Python by joining each term manually:
SELECT f.id FROM foo f
JOIN foo_bar fb ON fb.foo_id = f.id
JOIN bar b ON fb.bar_id = b.id AND b.name = 'Ruby'
JOIN foo_bar fb2 ON fb2.foo_id = f.id
JOIN bar b2 ON fb2.bar_id = b2.id AND b2.name = 'Python'
This gives 2 as the only id that haves all languages present.
I'm working on a PHP project with MYSQL database. I have a table of groups of students. Each group has an examiner. What i want to do is that i want to set two examiners for each group randomly. How to do it?
MySQL Code:
create table groups (
groupID int(10) not null,
nbStudents int not null,
avgGPA DOUBLE NOT NULL,
projectName varchar(50) not null,
advisorID int,
examiner1ID int,
examiner2ID int,
adminID int not null,
primary key (groupID)
);
create table faculty (
name varchar(30) not null,
facultyID int(10) not null,
email varchar(30) not null,
mobile int(15) not null,
primary key (facultyID)
);
examiner1ID and examiner2ID are foreign keys from the table faculty.
Here is a very convoluted way to do it. It uses 2 subqueries to pick faculty members, and insert .. on duplicate key to update the examiners IDs.
insert into groups
(groupID, examiner1ID, examiner2ID)
select groupID,
#x:=(select facultyID from faculty order by rand() limit 1),
(select facultyID from faculty where facultyID <> #x order by rand() limit 1)
from groups
on duplicate key update examiner1ID=values(examiner1ID), examiner2ID=values(examiner2ID);
#x is a user-defined-variable. In this case, it is used to store the first random faculty member. <> #x makes sure we don't pick the same faculty member in both slots.
Since groupID is a unique key, when we try to insert a row with an existing unique key, it will update the existing row instead of inserting it. That's what on duplicate key update clause is used for.
set different examiners for each group:
insert into groups
(groupID, examier1ID, examier2ID)
select a.groupID, max(if(b.id%2, b.facultyID, 0)), max(if(b.id%2, 0, b.facultyID))
from (
select #row:=#row+1 id, groupID
from groups a
join (select #row:=0) b) a
join (
select #row:=#row+1 id, facultyID
from (
select facultyID
from faculty a
order by rand()) a
join (select #row:=0) b) b on a.id = ceil(b.id/2)
group by a.groupID
on duplicate key update examiner1ID=values(examiner1ID), examiner2ID=values(examiner2ID);
I'm using a MySQL database which has a 'Staff' column. Example:
ID BUSINESS STAFF
1 Business 1 Bob
2 Business 2 Bill
3 Business 3 Paul, Bill
4 Business 4 Bob
I'm aiming to create a pie chart showing how many businesses each member of staff has, using the Google Charts API, and I'm having trouble counting total amounts.
The chart uses the formatting:
var data = google.visualization.arrayToDataTable([
['Staff', 'Business'],
['Bob', 2],
['Bill', 2],
['Paul', 1]
]);
How would I go about echoing a count of these lines? I've spent a fun 40 minutes messing up COUNT queries, with absolutely no joy.
There is a common theme in the comments here and that is normalization. As a rule it is A Bad Thing to represent multiple values as a comma-separated list in a single column.
Here is a working example of an alternate DB design that should get you going in the right direction:
create table staff
(
id int unsigned not null primary key auto_increment,
staffName varchar(250),
unique key `staffUIdx1` (staffName)
) ENGINE=InnoDB;
create table business
(
id int unsigned not null primary key auto_increment,
businessName varchar(250),
unique key `staffUIdx1` (businessName)
) ENGINE=InnoDB;
CREATE TABLE staffBusiness
(
id int unsigned not null primary key auto_increment,
staffId int unsigned not null,
businessId int unsigned not null,
unique key `staffBusinessUIdx1` (staffId,businessId),
CONSTRAINT `fk_staffBusiness_staff1` FOREIGN KEY (`staffId`) REFERENCES `staff` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION,
CONSTRAINT `fk_staffBusiness_business1` FOREIGN KEY (`businessId`) REFERENCES `business` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION
) ENGINE=InnoDB;
insert into staff (staffName) values ('Bob');
insert into staff (staffName) values ('Bill');
insert into staff (staffName) values ('Paul');
insert into staff (staffName) values ('George');
insert into business (businessName) values ('Business 1');
insert into business (businessName) values ('Business 2');
insert into business (businessName) values ('Business 3');
insert into business (businessName) values ('Business 4');
insert into staffBusiness (staffId,businessId)
select s.id,b.id from staff s join business b
where s.staffName = 'Bob' and b.businessName in ('Business 1','Business 4');
insert into staffBusiness (staffId,businessId)
select s.id,b.id from staff s join business b
where s.staffName = 'Bill' and b.businessName in ('Business 2','Business 3');
insert into staffBusiness (staffId,businessId)
select s.id,b.id from staff s join business b
where s.staffName = 'Paul' and b.businessName in ('Business 3');
...and then the query would look like this:
select staffName as Staff,count(sb.id) as Business
from staff s
left outer join staffBusiness sb on s.id = sb.staffId
group by staffName;
I've included a 4th member of staff called 'George' to show that a normalized approach allows you to have members of staff with no business too.
I develop this code according your question ,you should change according your table and fields also change server configuration server name,user,password,database
$server="server";
$user="user";
$password="password";
$database="database";
$cid=mysql_connect($server,$user,$password);
mysql_select_db($database,$cid);
$query="select * from table";
$rs=mysql_query($query,$conn);
$val=0;
while($row=mysql_fetch_array($rs))
{
$data=$row['business'];
$val=$val+trim(str_replace("Business","", "$data"));
}
$total=$val;
I used this code and i found total ;
I've been looking at this far too long and my brain feels like spaghetti noodles. Could someone help me out with a couple of queries?
Tables:
Presentation
------------
id int
name varchar
fk_template int (references template.id)
Template
--------
id int
name varchar
Position
--------
id int
zorder int (if it is the 1st, 2nd, 3rd position of the given template)
fk_template int (references Template.id)
Asset
-----
id int
name varchar
description varchar
AssetForPresentation
--------------------
fk_asset int (references Asset.id)
fk_presentation int (references Presentation.id)
fk_position int (references Position.id)
What I think I need to be asking at this point is basically "give me all of the assets AND their positions for this template."
You see, when a Presentation is brought it, it has a specific Template. Each Template has designated Positions, and each Position holds an Asset or NULL.
I need to be able to bring in all Assets and their individual positions for a particular Template used by a Presentation. How would I query for something like that?
I hope this makes sense to you.
I think the part you're having hard time with is two conditions on JOIN to the AssetForPresentation table.
SELECT
a.id,
a.name,
a.description
FROM Presentation AS p
JOIN Template AS t
ON p.fk_template = t.id
LEFT JOIN Position AS pos
ON pos.fk_template = t.id
LEFT JOIN AssetForPresentation AS afp
ON afp.fk_presentation = p.id
AND afp.fk_position = pos.id
LEFT JOIN Asset AS a
ON a.id = afp.fk_asset
WHERE p.id = 123
ORDER BY pos.zorder ASC
Based on what you have described in your question, you need to get all assets for a given template. I have created the table structure but didn't define the relation constraints on the table but used them while formulating the query.
You can join the Asset table to the AssetForPresentation table. Through AssetForPresentation table, you can join the Presentation and Position tables. The relation to the Template can be made through the Position table. Thus, joining the Template table to the Asset table to fetch all matching records.
You can view the demo in the below link.
Click here to view the demo in SQL Fiddle.
Hope that helps.
Script:
CREATE TABLE Presentation
(
id INT NOT NULL AUTO_INCREMENT
, name VARCHAR(30) NOT NULL
, PRIMARY KEY (id)
);
CREATE TABLE Template
(
id INT NOT NULL AUTO_INCREMENT
, name VARCHAR(30) NOT NULL
, PRIMARY KEY (id)
);
CREATE TABLE Position
(
id INT NOT NULL AUTO_INCREMENT
, zorder INT NOT NULL
, fk_template INT NOT NULL
, PRIMARY KEY (id)
);
CREATE TABLE Asset
(
id INT NOT NULL AUTO_INCREMENT
, name VARCHAR(30) NOT NULL
, description VARCHAR(30) NOT NULL
, PRIMARY KEY (id)
);
CREATE TABLE AssetForPresentation
(
fk_asset INT NOT NULL
, fk_presentation INT NOT NULL
, fk_position INT NOT NULL
);
INSERT INTO Presentation (name) VALUES
('presenation 1'),
('presenation 2');
INSERT INTO Template (name) VALUES
('template 1'),
('template 2');
INSERT INTO Position (zorder, fk_template) VALUES
(1, 1),
(2, 2);
INSERT INTO Asset (name, description) VALUES
('asset 1', 'asset description 1'),
('asset 2', 'asset description 2');
INSERT INTO AssetForPresentation (fk_asset, fk_presentation, fk_position)
VALUES
(1, 1, 1),
(1, 2, 1),
(2, 2, 1),
(2, 2, 2);
SELECT *
FROM Asset A
RIGHT OUTER JOIN AssetForPresentation AP
ON A.id = AP.fk_asset
RIGHT OUTER JOIN Presentation P
ON P.id = AP.fk_presentation
RIGHT OUTER JOIN Position PO
ON PO.id = AP.fk_position
RIGHT OUTER JOIN Template T
ON T.id = PO.fk_template
WHERE T.id = 1;
Output:
ID NAME DESCRIPTION FK_ASSET FK_PRESENTATION FK_POSITION ZORDER FK_TEMPLATE
-- ------- ------------------- -------- --------------- ----------- ------ -----------
1 asset 1 asset description 1 1 1 1 1 1
1 asset 1 asset description 1 1 2 1 1 1
2 asset 2 asset description 2 2 2 1 1 1
Here is my DB Structure:
CREATE TABLE IF NOT EXISTS `UserItems` (
`id` bigint(20) unsigned NOT NULL auto_increment,
`user_id` int(10) unsigned NOT NULL,
`item_id` int(10) unsigned NOT NULL,
`qty` int(11) NOT NULL default '0'
) ;
CREATE TABLE IF NOT EXISTS `UserEquippedItems` (
`user_id` int(10) unsigned NOT NULL,
`user_item_id` bigint(20) unsigned NOT NULL
);
CREATE TABLE IF NOT EXISTS `UserFriendEquippedItems` (
`user_friend_id` int(10) unsigned NOT NULL,
`user_item_id` bigint(20) unsigned NOT NULL
);
UserItems keeps all the item inventory with quantity.
let say if I have 5 item (item id 123456). then the entry will be
(null, $userid, 123456, 5).
the qty is the quantity of all the entity with the same item_id.
However, some Users may equip the item. Some do not. If they equip it, it will be an entry in UserEquippedItems table.
Also, users' friends can equip the user's item too.
Sample Data:
UserItems:
id, user_id, item_id, qty
( 1, 4567, 123123123, 5)
( 2, 4567, 100010001, 2)
( 3, 4567, 100010099, 1)
UserEquippedItems: (user_item_id is UserItems.id)
user_id, user_item_id
( 4567, 1)
( 4567, 2)
UserFriendEquippedItems
(user_item_id is UserItems.id)
user_friend_id, user_item_id
( 4100, 1)
( 4100, 3)
So, how can I find out the quantity of items that are equipped?
and how can I find out the quantity of items that are NOT equipped ?
Side Story: Before, we have each individual UserItems as a single entry in the DB. e.g. for item_id = 123123123, if I have 5 of them, i have 5 entries in the DB. But then, our DB grows like crazy to 4 million UserItems records. that's why instead of having 5 entries, we only have one entry in the UserItems table, with the qty field for keep track how many in total. I don't know if it is the right approach, but I hope it can cut down 75% of the DB size.
Also, it was the query to get the unequipped items:
SELECT Items.id, count(UserItems.id) as numCount
FROM UserItems INNER JOIN
Items ON UserItems.active=1 AND
UserItems.item_id=Items.id AND
Items.active=1 AND
UserItems.user_id=$userId
WHERE NOT EXISTS (
SELECT UserEquippedItems.user_item_id
FROM UserEquippedItems
WHERE UserEquippedItems.user_item_id= UserItems.id
)
AND NOT EXISTS (
SELECT UserFriendsEquippedItems.user_item_id
FROM UserFriendsEquippedItems
WHERE UserFriendsEquippedItems.user_item_id= UserItems.id)
GROUP BY Items.id
Of course, this query doesn't work with the new schema. :)
This should work:
SELECT id, user_id, item_id, qty,
(SELECT COUNT(*) FROM UserEquippedItems uei
WHERE uei.user_item_id=ui.id) as qty_equipped,
(SELECT COUNT(*) FROM UserFriendEquippedItems ufei
WHERE ufei.user_item_id=ui.id) as qty_friend_equipped
FROM UserItems ui
Then to get the unequipped, on your client you can subtract the qty_equipped and qty_friend_equipped from qty.
A single query that just returns unequipped:
SELECT id, user_id, item_id, qty,
qty-
(SELECT COUNT(*) FROM UserEquippedItems uei
WHERE uei.user_item_id=ui.id)-
(SELECT COUNT(*) FROM UserFriendEquippedItems ufei
WHERE ufei.user_item_id=ui.id)
as qty_unequipped
FROM UserItems ui
You could combine those 2 queries above into one big query, but I image that would hurt performance, since it will run the sub-queries twice.
You can add a WHERE clause on the end of both of these to return results for a specific user / item.
To count the total number of items equipped:
SELECT count(*) FROM UserEquippedItems e JOIN UserItems i ON (i.id = e.user_item_id)
To find the total number of items of id $item_id equipped
SELECT count(*) FROM UserEquippedItems e WHERE e.user_item_id = $item_id
And to find the total number of items user $user_id has equipped (my first response, though probably not what you're after)
SELECT count(*) FROM UserEquippedItems WHERE user_id = $user_id