Database Design/Structure -- Collecting Data over time - php

currently I am in the process of structuring a database for a site I am creating. However, I have come across a problem. I want to log the amount of times a user has logged in each day, and then be able to keep track of that info over large periods of time such as a 8 months, a year, 2 years, etc.
The only way I can think of right now, is to just have a column for each day of the year/automatically create a column each day. This idea however, just seems plain stupid to me. I'm sure there has to be a better way to do this, I just can't think of one.
Any suggestions?
Thanks,
Rob

Create a separate table where you store user_id, and datetime the user logs in.
Averytime the user logs in, you insert a new record on this table.
Example:
CREATE TABLE user_activity (
userid varchar(50),
log_in_datetime datetime
);

Here is a login table I use for one of my sites. The datetime can either be logged as a datetime or as a timestamp. If you use datetime make sure to consider the timezone of your mysql server.
There is plenty of stuff to track. Then you can just query it later. Each of these column names should be self explanatory with a google search.
CREATE TABLE `t_login` (
`id_login` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
`id_user` INT(10) UNSIGNED NOT NULL DEFAULT '0',
`id_visit` INT(10) UNSIGNED NOT NULL DEFAULT '0' COMMENT 'fk to t_visit',
`id_org` INT(10) UNSIGNED NOT NULL DEFAULT '0',
`when_attempt` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
`uname_attempt` VARCHAR(100) NOT NULL DEFAULT '' COMMENT 'attempted username' COLLATE 'latin1_swedish_ci',
`valid_uname` TINYINT(1) UNSIGNED NOT NULL DEFAULT '0' COMMENT 'valid username',
`valid_uname_pword` TINYINT(1) UNSIGNED NOT NULL DEFAULT '0' COMMENT 'valid username and valid password together',
`pw_hash_attempt` BINARY(32) NOT NULL DEFAULT '\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0',
`remote_ip` CHAR(20) NOT NULL DEFAULT '' COLLATE 'latin1_swedish_ci',
`user_agent` VARCHAR(2000) NOT NULL DEFAULT '' COLLATE 'latin1_swedish_ci',
PRIMARY KEY (`id_login`),
INDEX `when_attempt` (`when_attempt`),
INDEX `rempte_ip` (`remote_ip`),
INDEX `valid_user` (`valid_uname`),
INDEX `valid_password` (`valid_uname_pword`),
INDEX `username` (`uname_attempt`),
INDEX `id_ten` (`id_org`),
INDEX `id_user` (`id_user`),
INDEX `id_visit` (`id_visit`)
)
COLLATE='utf8_general_ci'
ENGINE=InnoDB
AUTO_INCREMENT=429;

Related

How to speed up the SELECT query of the following table?

I have a mysql table whose create code is as follows :
CREATE TABLE image_ref (
region VARCHAR(50) NULL DEFAULT NULL,
district VARCHAR(50) NULL DEFAULT NULL,
district_name VARCHAR(100) NULL DEFAULT NULL,
lot_no VARCHAR(10) NULL DEFAULT NULL,
sp_no VARCHAR(10) NULL DEFAULT NULL,
name VARCHAR(200) NULL DEFAULT NULL,
form_no VARCHAR(50) NOT NULL DEFAULT '',
imagename VARCHAR(50) NULL DEFAULT NULL,
updated_by VARCHAR(50) NULL DEFAULT NULL,
update_log DATETIME NULL DEFAULT NULL,
ip VARCHAR(50) NULL DEFAULT NULL,
imgfetchstat VARCHAR(1) NULL DEFAULT NULL,
PRIMARY KEY (form_no)
)
COLLATE='latin1_swedish_ci'
ENGINE=MyISAM;
This table contains approximately 7,00,000 number of rows. I have an application developed using PHP. Somewhere I need to run the following query :
SELECT
min(imagename) imagename
FROM
image_ref
WHERE
district_name = '$sess_district'
AND
lot_no = '$sess_lotno'
AND
imgfetchstat = '0';
which is taking on average 1.560 sec. The form_no field only has unique values. After some job is done with the result set fetched, the imgfetchstat is required to be updated with a value 1. Now my requirement is that, whether I should use InnoDB or MyISAM? Also, the application is accessed by around 50 numbers of users in LAN. Is there any way out to run the above query little bit faster? because the imagename fetched is being used to load an image of resolution 500 x 498 into the browser and the it is taking enough time to load the image. Thanks in advance.
You can add indexes to your table (be aware that this will make the storage larger - but given your query, you should be able to use the following:
ALTER TABLE `table` ADD INDEX `product_id` (`product_id`)
For more information see http://dev.mysql.com/doc/refman/5.0/en/create-index.html
You can add an index on a single column (which makes things nice for the DB, even it it uses a few of them on a query) but if you have a secific query that needs to REALLY run fast, you can add a multi-column index which is specific to your query:
ALTER TABLE image_ref ADD INDEX `someName`
(`district_name`, `lot_no`, `imgfetchstat`)

CakePHP 1.3 - create() not setting created datetime?

I'm upgrading a system from CakePHP 1.1 to 1.3. When using create() (followed by save()) in 1.1 the system would happily add an insert an entry to the database with the created and modified datetime fields set to that of the time it was created. However, in 1.3 this is no longer correctly happening. Here the modified is still set to the current time upon the creation and save, but the created datetime is not being set. Any suggestions as to why this might be occurring? Thanks!
Create Table Code (as requested in comment):
CREATE TABLE `units` (
`id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
`id_b36` VARCHAR(4) NULL DEFAULT NULL,
`subject_id` INT(10) UNSIGNED NOT NULL,
`gradelevel_id` INT(10) UNSIGNED NOT NULL,
`user_id` INT(10) UNSIGNED NOT NULL,
`school_id` INT(10) NULL DEFAULT NULL,
`district_id` INT(10) NULL DEFAULT NULL,
`description` VARCHAR(255) NOT NULL,
`sort` FLOAT(5,1) NOT NULL DEFAULT '0.0',
`created` DATETIME NOT NULL DEFAULT '0000-00-00 00:00:00',
`modified` DATETIME NOT NULL DEFAULT '0000-00-00 00:00:00',
PRIMARY KEY (`id`),
INDEX `subject_id` (`subject_id`),
INDEX `gradelevel_id` (`gradelevel_id`),
INDEX `sort` (`sort`),
INDEX `school_id` (`school_id`, `district_id`)
)
COLLATE='latin1_swedish_ci'
ENGINE=InnoDB
ROW_FORMAT=DEFAULT
AUTO_INCREMENT=483
I should note that this is just one of the tables, the same thing occurs on all other models. Thanks!
created DEFAULT NULL
CakePHP will only populate created if it is defined as NULL:
By defining a created and/or modified field in your database table as datetime fields (default null), CakePHP will recognize those fields and populate them automatically whenever a record is created ...

Different user roles for logging in with PHP and Mysql

I have a project coming up for doing Admin functions so my question is this. I will try and be clear as possible.
I will have one SUPER-USER who updates all information for other regular-users/people(being our clients).
The clients/regular-users when they log in will only see their info and download files uploaded by SUPER-USER and not see for regular-users.
So if you are Client:#01 you will see the dashboard (welcome page) and your info. Can anyone suggest possible database designs for this.
How to use left/right sql-joins between the user and files table?
UPDATE
I have a users table as well as a company table that the user belongs to. So essentially I want something like this::
$sql = select everything in the users table where the username and pass = to the given form, then left or right join that username to the company that he belong to.
Then they will see their information. if logged in successfully. Because user #01 belongs to company #03 /#01 etc...
USER TABLE looks so
`id` int(11) NOT NULL AUTO_INCREMENT,
`fname` varchar(50) NOT NULL,
'lname` varchar(100) NOT NULL,
`username` varchar(50) ,
`password` varchar(100) ,
`company` varchar(50) // the company name that ther user belongs to
PRIMARY KEY (`id`)
COMPANY table
'id' int(11) not null auto_increment,
'user_id' int(11) //This is to tie the users to this table
'description' varchar(text),
'filename' varchar(25) not null,
'mimetype' varchar (25) not null
PRIMARY KEY ('id')
Well, it depends on how simple or complex you want to go. with something like this I usually will keep it relatively simple and have a main user database (for all users) example:
CREATE TABLE IF NOT EXISTS `user` (
`user_id` int(255) NOT NULL AUTO_INCREMENT,
`user_name` varchar(50) NOT NULL,
`user_pass` varchar(100) NOT NULL,
`user_permissions` tinyint(1) NOT NULL DEFAULT '0',
`active` tinyint(1) NOT NULL DEFAULT '1',
`date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
) ENGINE=MYISAM;
Then I would have possible a second table of permissions depending on how many permissions I was going to have. If all you are going to have is users and super users then you could probably just assign users a value of 0 and then super user a value of 1.
Then in your PHP script it would treat the users different based on their "user_permissions" value.
Now if you are intending to have lots of different levels of permissions then I would definitely create at least one more table to define permissions example:
CREATE TABLE IF NOT EXISTS `permission` (
`permission_id` int(255) NOT NULL AUTO_INCREMENT,
`permission_name` varchar(100) NOT NULL,
`permission_value` int(10) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MYISAM;
Then in the permissions table you could assign all sorts of different permissions... read, write, publish, admin, regular user, super user etc.
This is just a very simple starting point. hope that helps.

PHP model (MySQL) design problem

I'm looking for the most efficient solution to the problem I'm running into. I'm designing a shift calendar for our employees. This is the table I'm working with so far:
CREATE TABLE IF NOT EXISTS `Shift` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`accountId` smallint(6) unsigned NOT NULL,
`grpId` smallint(6) unsigned NOT NULL,
`locationId` smallint(6) unsigned NOT NULL,
`unitId` smallint(6) unsigned NOT NULL,
`shiftTypeId` smallint(6) unsigned NOT NULL,
`startDate` date NOT NULL,
`endDate` date NOT NULL,
`needFlt` bit(1) NOT NULL DEFAULT b'1',
`needBillet` bit(1) NOT NULL DEFAULT b'1',
`fltArr` varchar(10) NOT NULL,
`fltDep` varchar(10) NOT NULL,
`fltArrMade` bit(1) NOT NULL DEFAULT b'0',
`fltDepMade` bit(1) NOT NULL DEFAULT b'0',
`billetArrMade` bit(1) NOT NULL DEFAULT b'0',
`billetDepMade` bit(1) NOT NULL DEFAULT b'0',
`FacilityId` smallint(6) unsigned NOT NULL,
`FacilityWingId` mediumint(9) unsigned NOT NULL,
`FacilityRoomId` int(11) unsigned NOT NULL,
`comment` varchar(255) NOT NULL,
`creation` datetime NOT NULL,
`lastUpdate` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
`lastUpdateBy` mediumint(9) unsigned NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;
Now here's the hitch - I'd like to be able to display on the calendar (in a different color) whether or not a timesheet has been received for a certain day.
My first thought was to create a separate table and list separate entries by day for each employee, T/F. But the amount of data returned from a separate query, for each employee, for the whole month would surely be huge and inefficient.
Second thought was to somehow put the information in this Shift table, with delimiters - then exploding it with PHP. Silly idea... but I guess that's why im here. Any thoughts?
Thanks for your help!
As hinted previously and I think you realized yourself, serializing the data into a single column or using some other form of delimited string is a path to computational inefficiencies in the packing and unpacking and serious maintenance grief for the future.
Heaps better is to get the data structure right, i.e. a properly normalized table. After all, MySQL is rather good at dealing with this some of structure.
You don't need to pull back every line for every staff member. If you're pull them out together, you could "group" your resultset by employee and date, and even make that a potentially useful result by (say) pulling the summary of hours. A zero result or null result would show no timesheet, and the total hours may be helpful in some other way.
If you were pulling them out an employee and a date at a time then your application structure probably needs looking at, but you could use the SQL LIMIT keyword to pull at most one record and then test to see if any came back.

Database structure for social login implementation?

In my application, I have a "user" table that has the following structure.
CREATE TABLE IF NOT EXISTS `users` (
`userId` int(10) unsigned NOT NULL auto_increment,
`username` varchar(128) NOT NULL default '',
`password` varchar(32) NOT NULL default '',
`email` text NOT NULL,
`newsletter` tinyint(1) NOT NULL default '0',
`banned` enum('yes','no') NOT NULL default 'no',
`admin` enum('yes','no') NOT NULL default 'no',
`signup_ip` varchar(20) NOT NULL default '',
`activation_key` varchar(60) NOT NULL default '',
`resetpassword_key` varchar(60) NOT NULL default '',
`createdon` datetime NOT NULL default '0000-00-00 00:00:00',
PRIMARY KEY (`userId`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=27 ;
I want to implement social login via Facebook, Twitter, and OpenID in my application, just like Stack Overflow did.
I would suggest that you introduce the concept of an AuthenticationProvider:
CREATE TABLE IF NOT EXISTS `AuthenticationProvider` (
`ProviderKey` varchar(128) NOT NULL,
`userId` int(10) unsigned NOT NULL,
`ProviderType` enum('facebook','twitter', 'google') NOT NULL,
PRIMARY KEY (`ProviderKey`) )
ENGINE=MyISAM DEFAULT CHARSET=latin1;
Each login provider provides a unique key for the user. This is stored in ProviderKey. The ProviderType contains information about which login provider this ProviderKey belongs to, and finally, the userId column couples the information with the users table. So when you receive a succesful login from one of the login providers you find the corresponding ProviderKey in the table and use set the authentication cookie for the user in question.
I'm not sure that you want the ProviderType to be an enum. It would probably be more correct to make another table that could hold these.
When a user first registers with your site, and logs in via Facebook, for example, you will have to create a row in the users table. However, there will be no password, activation_key and resetpassword_key involved. So you may want to move those fields to a separate table, such that your users table only contains the core user data, and no data that is only relevant for a single login mechanism (username/password).
I hope this makes sense and that it points you in the right direction.
/Klaus

Categories