How should i store entities with only a few possible values? - php

How should i store data like users's gender, religion, political views which is selecting from a list of 2-8 max values like 'male', 'female' or 'orthodox', 'muslim','judaism','catholic' etc? Also this values is constant, even admin cannot change 'female' to something else. In a Database it looks wierd to store a similar tables with only this 2-8 values and make JOIN with a parent table on foreign key. Second way - special object inside program code - but it's always bad to mix program logic with a data.

Whether or not something is looking "weird" depends on personal preferences or design structures. However, it is entirely logical to store anything in a database that has to do with, well, data. Even a given set of options can change in the distant or not so distant future. I can't count the times a client asked me to change a set of options a day, a week, or even a few years after having ensured me that the set wouldn't change, ever.
Storing a list of options in a separate table is part of a relational database design. Relational database designs make it easy to get a set of data which includes or even excludes the options in any way in my opinion.
I'd recommend doing it the good, old fashioned way, for example:
Table user (id, user_name)
Table option (id, option_label)
Table user_option (id, user_id, option_id)
A user that is both male and catholic would have a relation with two options:
Table user Table option Table user_option
+----+-----------+ +----+--------------+ +----+---------+-----------+
| id | user_name | | id | option_label | | id | user_id | option_id |
+----+-----------+ +----+--------------+ +----+---------+-----------+
| 1 | john | | 1 | male | | 1 | 1 | 1 |
| 2 | melody | | 2 | female | | 2 | 1 | 6 |
| 3 | gerald | | 3 | orthodox | +----+---------+-----------+
+----+-----------+ | 4 | muslim |
| 5 | judaism |
| 6 | catholic |
+----+--------------+
Showing all selected options per user can be done with the following query:
SELECT `u`.*, GROUP_CONCAT( `o`.`option_label` SEPARATOR ', ' ) AS `options`
FROM `user` AS `u`
LEFT JOIN `user_option` AS `uo` ON `uo`.`user_id` = `u`.`id`
LEFT JOIN `option` AS `o` ON `uo`.`option_id` = `o`.`id`

It must go in a table, even if it make you makes joins. The join will be done over a PK, so there is little overhead

Related

Check if value exists in MySQL table and then select [Laravel 5]

Here is my pivot table project_group:
+-----+----------+------------+----------+---------+
| ids | group_id | project_id | admin_id | user_id |
+-----+----------+------------+----------+---------+
| 4 | 115 | 1 | 1 | [3,4,5] |
| 5 | 115 | 2 | 1 | [5,2,1] |
| 6 | 115 | 3 | 1 | [1,3,6] |
This table represent group linked to the projects....user_id is which users can see projects/group... Is there any way to display correct projects/group only to the users defined in user_id?
Also content in user_id field can be changed....
The best way to handle this would be to first normalize your database. Storing comma separated lists in a cell is allowed, but generally bad practice, as explained in this question.
If you can have multiple users per project, you should have a linking table with a column for project and a column for user, like this:
project_users:
| project_id | user_id |
and you can make (project_id, user_id) a composite primary key.
That way, you can select the users for a project (say, project 1) like this:
SELECT user_id
FROM project_users
WHERE project_id = 1;
Once you have these, you can display the project data only to users whose id is returned in the above list.
I have built an SQL Fiddle that helps demonstrate this visually, if it helps.
It is good to note that this proper normalization gives the opportunity to a lot of useful data as well, as it becomes easier to search for users by project, but also you can search for project information based on a user.

count number of rows that have the same combination of two colums

Hi I have 2 table Offense table and User_jobs table
offense table:
crime_id |crime_type |casenumber|
---------+-----------+----------+
1 | 3 |1 |
2 | 3 |1 |
1 | 3 |2 |
12 | AA |2 |
user_jobs table:
casenumber |disposal_status |
-----------+----------------+
1 | yes |
1 | yes |
2 | no |
2 | no |
what i want is to count the number of rows with the same combination say crime_id=1 and crime_type= 3 but these must have a disposal status of yes in the user_jobs table.
i want to do this in mysql. pliz help
sorry but i am new to mysql. i now want to display the real names of those id not the id themselves.
the tables with these IDs are crime_category and Crime_type Crime_catgory
table:
category |crime_id |
-----------+----------------+
theft | 1 |
murder | 2 |
rape | 3 | 2 |
no |
Crime_type table:
Crime_type |id |
---------------+----------------+
administrative | yes |
criminal | yes |
You can do this with a simple inner join and an aggregate function:
select
o.crime_id,
o.crime_type,
count(*)
from
offence o
join user_jobs uj
on o.casenumber=uj.casenumber
where
uj.disposal_status='Yes'
group by
o.crime_id,
o.crime_type
This will pick up distinct combinations of the first two columns joined as they should tot he jobs table and only where the disposal_status is equal to 'Yes'
Edit: You would probably do really well to have a read of this Q&A that I put together for exactly this sort of situation - where I give you the code for it, but would like to explain this is a lot more detail. The Q&A explains why this type of thing (and many many others) work and how they do so:
How can an SQL query return data from multiple tables
Edit 2:
select
o.crime_id,
o.crime_type,
ct.category,
count(*)
from
offence o
join user_jobs uj
on o.casenumber=uj.casenumber
join crime_type ct
on o.crime_type=ct.crime_id
where
uj.disposal_status='Yes'
group by
o.crime_id,
o.crime_type,
ct.category,

Database Schema suggestions please

I have a scenario and i'm confused about how i can go about designing the database schema for it.
In my software (php)
there are companies and applications.
companies need to have licenses to access applications.
now the fields (for form while purchasing licenses) for each application is different.
for ex:
for application1:
fields are:
no of users
no of groups
for application2:
no of users
for application3:
number of hours of usage
Prices are based on these fields.
Now i need to design schema for this so that on one page company can manage licenses for all applications.
How can i make this schema generic?
Please help.
Thanks.
You can go with this type of structure
select * from applicationMaster
| APPID | APPNAME |
------------------------
| 1 | Application1 |
| 2 | Application2 |
ApplicationMaster will go with main Application related details which won't be repeated such Name, date etc.
Query 2:
select * from applicationField
| FIELDID | APPID | FIELDNAME |
---------------------------------
| 1 | 1 | NoOfUsers |
| 2 | 1 | NoOfGroups |
| 3 | 2 | NoHourusage |
ApplicationField can adjust any number of field for a particular appId.
So AppId 1 has 2 fields NoofUsers and NoOfGroups. It is also capable to adjust newer fields for a particular app if you want.
Query 3:
ApplicationValue will have the values for every license aplication so it will have compId which represents which company has applied using fieldId which refers to applicationField table we can get for which app values are stored.
select * from applicationValue
| ID | COMPID | FIELDID | FIELDVALUE |
--------------------------------------
| 1 | 1 | 1 | 50 |
| 2 | 1 | 2 | 150 |
| 3 | 2 | 3 | 350 |
| 4 | 3 | 1 | 450 |
| 5 | 3 | 2 | 50 |
applicationPriceMaster stores the price package for each application. There could be multiple package for a application.
select * from applicationPriceMaster
| APPPACKAGE | APPID | TOTALPRICE |
-----------------------------------
| 1 | 1 | 50 |
| 2 | 1 | 100 |
For each application package its details will posted in this table.
select * from applicationPriceDetail
| APPPACKAGE | FIELDID | QUANT |
--------------------------------
| 1 | 1 | 1 |
| 1 | 2 | 1 |
| 2 | 1 | 10 |
| 2 | 2 | 1 |
NOTE Please check the structure as it is now too complex and check what type of queries you would be running on these table and its performance.
select apm.APPPACKAGE, TOTALPRICE from
applicationPriceMaster apm
inner join
(select APPPACKAGE from applicationPriceDetail
where FIELDID=1 and QUANT=1)a
on apm.APPPACKAGE = a.APPPACKAGE
inner join
(select APPPACKAGE from applicationPriceDetail
where FIELDID=2 and QUANT=1)b
on
a.APPPACKAGE=b.APPPACKAGE
SQL FIDDLE:
| APPPACKAGE | TOTALPRICE |
---------------------------
| 1 | 50 |
For single filter you have to use this query, so you have to increase number of inner query with the number of inner filter.
select apm.APPPACKAGE, TOTALPRICE from
applicationPriceMaster apm
inner join
(select APPPACKAGE from applicationPriceDetail
where FIELDID=1 and QUANT=1)a
on apm.APPPACKAGE = a.APPPACKAGE
NOTE-This query is quite complex and will only work if the values are same as mentioned in the packagedetail table and will work only if the values are 2 filter you have to remove 1 inner join if there is only 1 filter. So I suggest you to reconsider before using this approach.
What you have there, could be easily mapped to Classes in an OO language (like PHP). You have an Abstract License, and then 3 Subclasses (ApplicationByUsersAndGroups, etc). Then, mapping to a Relational database is a very common problem, here is a nice article about it: http://www.ibm.com/developerworks/library/ws-mapping-to-rdb/
It has 3 options, it depends on the way you want to structure your application which one you should use. I recommend reading it, it is not that long.
One way is
Table LICENCES:
LICENSE_ID ==> UNIQUE IDENTIFIER
COMPANY_ID ==> references table COMPANIES
APPLICATION_ID ==> references table APPLICATIONS
LICENCE_TYPE ==> either of "BY_GROUPS_AND_USERS", "BY_USERS", "BY_HOURS"
LICENCE_BODY_ID ==> ID of specific body table
[...]
Table LIC_TYPE_BY_GROUPS_AND_USERS:
LICENCE_BODY_ID ==> body identifier
NO_GROUP
NO_USERS
[...]
Table LIC_TYPE_BY_USERS:
LICENCE_BODY_ID ==> body identifier
NO_USERS
[...]
This way, your intention is clear. Even after long time comming back, you will know in no time how things are organized, which fields are used in which case...
how about a table structured this way:
LicenseId int PK
CompanyId Int PK
AppId Int PK
LicenseType int
NumberOfUsers int
NumberOfGroups int
NumberOfHours int
Price Money
Depending on LicenseType, you will use different column in your business logic,
you might need to add CompanyID and/or AppID, that depends how you going to structure those tables as well as relation ships between company/app/license.
Some questions to think about:
Can one company have different License Types for same App?
Can one company have different Apps?
Dont complicate things, if the number of users is unlimited then set it to 999999 or some other max value.
This keeps the license check logic (which will run every time a user logs in ) simple and the same for all applications.
You will need extra logic in the licenses maintenance application, but this should also be pretty simple:
if the cost_per_user is = 0 then set no_of_users = 99999
Again you end up with the same licensing screen and logic for all your applications.

Have SQL Table Fields Automatically Link to Lookup Tables

I have a few tables in a MySQL database similar to this setup:
major table
---------------------
| id | name |
|-------------------|
| 0 | Architecture |
| 1 | Biology |
| 2 | Chemistry |
---------------------
college table
----------------------
| id | name |
|--------------------|
| 0 | Georgia Tech |
| 1 | Virginia Tech |
| 2 | Cal Tech |
----------------------
users table
----------------------------------------------
| id | name | major_id | college_id |
|--------------------------------------------|
| 0 | John Smith | 2 | 0 |
| 1 | Kevin Lee | 2 | 1 |
| 2 | Matt Anderson | 0 | 2 |
----------------------------------------------
Using PHP, I want to get all the information for a user using a query similar to this:
SELECT * FROM users WHERE name=`$user`
Is there someway for MySQL to automatically link the "major_id" and "college_id" columns to the "major" and "college" tables in a way where the query above would return the appropriate values?
If it is not possible with a single query, would multiple queries slow down performance considerably?
SELECT * FROM users WHERE name='$user'
This query (yours has back ticks around $user, back ticks are for column names, use double/single quotes) will only return values from the users table. You can't make MySQL "automagically" construct your joins. You have to do it explicitly, otherwise, how would you get information only from the users table if you wanted to? Use a JOIN like this:
SELECT users.name AS Username, college.name AS College, major.name AS Major
FROM users
INNER JOIN college ON users.college_id = college.id
INNER JOIN major ON users.major_id = major.id
Limit the retrieved columns by only selecting the ones you really need. So instead of the asterisk, write users.name etc.
The JOIN syntax is described in the MySQL Docs.
Joins are what your looking for, in this case your SQL would be:
SELECT `users`.`name`, `major`.`name`, `college`.`name`
FROM `users` WHERE `users`.`name`='name'
INNER JOIN `major` ON `major`.`id`=`users`.`major_id`
INNER JOIN `college` ON `college`.`id`=`users`.`college_id`
You can also alias your field names so you get something a bit more usable out:
SELECT `users`.`name` AS `applicant_name`, `major`.`name` AS `major_name`, `college`.`name` AS `college_name`
FROM `users` WHERE `users`.`name`='name'
INNER JOIN `major` ON `major`.`id`=`users`.`major_id`
INNER JOIN `college` ON `college`.`id`=`users`.`college_id`
More on Joins at http://dev.mysql.com/doc/refman/5.0/en/join.html

query to imlement block list

I have two tables a and b as follows to implement a simple block list where users can block other users.....
Table A
+------------+--------------+------+
| Name | phone |userid|
+------------+--------------+------+
| Mr Sasi | 01225 708225 | 1 |
| Miss Brown | 01225 899360 | 2 |
| Mr Black | 01380 724040 | 3 |
+------------+--------------+------+
Table B
+------------+--------------+
| blockedbyid| blockedid |
+------------+--------------+
| 1 | 2 |
| 2 | 3 |
| 1 | 3 |
+------------+--------------+
"blockedbyid" is id of user who has blocked the user in "blockedid".
I need to join the two tables and fetch all records from table A such that the result has all users who are not blocked by a particular user [ie blockedbyid='XXX'].. Can you guys give the SQL query so that i can fetch the records as a recordset??? I dont want to fetch two different rowsets and compare it in php....
Something like this should work
Parameter :USERID
SELECT * FROM TABLEA WHERE userid NOT IN (SELECT blockedid FROM TABLEB WHERE blockedbyid = :USERID)
Using join
SELECT u.* FROM TABLEB b, TABLEA u WHERE b.blockedbyid = 'XXX' AND b.blockedid = NULL
It may work like that, give it a try.
Roadie57 solutions seems better though.

Categories