Search and print result from multiple queries - php

I have 3 tables. service_robot_errorservice contains a foreign key that is primary key in the service table. robot_error does not have ore give any foreign keys.
TABLE: robot_error
| id | date | stop_time | start_time | robot | position | error_code | observation | solution | downtime | logged_by |
| 1 | 02.01.2012 | 14:51:31 | 14:52:00 | 20 | 25/7 | 214 | X dir | Rob off | 29 | XXX |
TABLE: service
| service_id | service_date | service_module | service_user | service_comment | service_type |
| 1 | 13.01.2012 | Robot | XXX | Test service | Errorservice |
TABLE: service_robot_errorservice
| errorservice_id | service_id | errorservice_robot | errorservice_tracksensor | errorservice_gripper |
| 5 | 1 | 54 | OK | OK |
When a user searches for a robot (eks 16) i want the result to be every instance in robot_error orderd by date AND if the robot has service registered this instance should also be shown in the result.
Example:
robot_error instance
robot_error instance
robot_error instance
service instance
robot_error instance
service instance
That is what i want the result to look. I've tryed to first get the result out of this SQL
SELECT * FROM robot_error WHERE robot = '16'
and make a while to loop all results in robot_error table but i cant figure out how i can make the result from service tables to be shown, can anyone help? :)

I'd recommend using joins.
JOIN: Return rows when there is at least one match in both tables
LEFT JOIN: Return all rows from the left table, even if there are no matches in the right table
RIGHT JOIN: Return all rows from the right table, even if there are no matches in the left table
FULL JOIN: Return rows when there is a match in one of the tables
But you'd have to have a relation between robot_error and service before you can use a query with a join. It would probably look something like this:
SELECT * FROM robot_error LEFT OUTER JOIN services ON robot_error.ID = services.FK WHERE robot = '16'
Jeff Atwood demonstrates the different Joins quite nicley

Related

Summation Query with join codeigniter

I have 2 tables. One with a list of clients and another with a list of data. I am trying to create a table in my view that lists the client name along with the sum of a column(job_total) in the data table. I am able to write a query that works fine in most situations. The problem is, if I have not yet created a record in the data table I need to still display the client name with a balance of zero on my table in my view. Need some direction on how to handle this. I was thinking I need to query my list of clients and loop through that query just not sure how to do it.
I want my view to look like below:
+-------------+---------+
| Client Name | Balance |
+-------------+---------+
| xxx | $75.00 |
| xxx | $100.00 |
| xxx | $0.00 |
+-------------+---------+
Here is a rough layout of the two tables in my database:
cj_clients
+----+-------------+
| id | client name |
+----+-------------+
| 1 | client1 |
| 2 | client2 |
| x | xxx |
+----+-------------+
cj_data
+----+-----------+-----------+
| id | client_id | job_total |
+----+-----------+-----------+
| 1 | 1 | 5.00 |
| 2 | 1 | 10.00 |
| 3 | 1 | 15.00 |
+----+-----------+-----------+
The below code returns the desired results except when no entries have yet been made to the cj_data table. Not sure how to still get the client in the table view with a balance of $0.
$this->db->select('client_name,client_id, sum(job_total) AS balance')
->from('cj_data')
->join('cj_clients','cj_data.client_id = cj_clients.id')
->group_by('client_name');
return $this->db->get()->result();
You need to give left join
$this->db->select('client_name,client_id, IFNULL(sum(job_total),0) AS balance')
->from('cj_data')
->join('cj_clients','cj_data.client_id = cj_clients.id',"left") // here
->group_by('client_name');
return $this->db->get()->result();
I wrote IFNULL condition if record not found or it will show all data for all clients in cj_clients
Note: the Default behaviour of CodeIgniter is it will add inner join
if join not specified

Mysql join query multiple values

I have a table called facility.
Structure looks as follows:
id | name
---------
1 | Hotel
2 | Hospital
3 | medical shop
I have an other table which is taking data from the above table and keeping multiple values in one column. View looks like below:
id | facilities
---------------
1 | Hospital~~medical shop~~Hotel
2 | Hospital~~Hotel
3 | medical shop~~Hotel
If I want to join these two tables how does the query look like?
I tried this, but it didn't work:
select overview.facilities as facility
from overview join facility on facility.id=overview.facilities;
you can do this with a bit of hackery
select o.facilities as facility
from overview o
join facility f on find_in_set(f.facilities, replace(o.facilities, '~~', ','));
I would highly recommend you change the way you are storing data. currently it is considered un normalized and that quickly becomes a monster to deal with
you should change your table structure to look something more like this
+----------+--------------+
| facility |
+----------+--------------+
| id | name |
+----------+--------------+
| 1 | Hotel |
| 2 | Hospital |
| 3 | medical shop |
+----------+--------------+
+-----------+-------------+
| overview |
+-----------+-------------+
| id | facility_id |
+-----------+-------------+
| 1 | 2 |
| 2 | 3 |
| 3 | 1 |
| 4 | 2 |
| 5 | 1 |
| 6 | 3 |
| 7 | 1 |
+-----------+-------------+
Code Explanation:
basically you are wanting to find the matching facilities in the overview. one handy function MySQL has is FIND_IN_SET() that allows you to find an item in a comma separated string aka find_in_set(25, '11,23,25,26) would return true and that matching row would be returned... you are separating your facilities with the delimiter ~~ which wont work with find_in_set... so I used REPLACE() to change the ~~ to a comma and then used that in the JOIN condition. you can go from here in multiple ways.. for instance lets say you want the facility id's for the overview.. you just add in the select GROUP_CONCAT(f.id) and you have all of the id's... note if you do that you need to add a GROUP BY at the end of your query to tell it how you want the results grouped

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.

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.

How to efficiently do this mysql query? (Join and Check existence)

I'm doing a mysql query where I want to join two tables (Projects and Country):
+----------------+ +-------------------------+
| Project ID | | id |
+----------------+ +-------------------------+
| Name | | name |
+----------------+ +-------------------------+
| countryid | | lat, long (two columns) |
+----------------+ +-------------------------+
I'm using this query:
SELECT country.name, country.latitude, country.longitude
FROM projects JOIN country ON projects.countryid = country.id;
Fine until now! What happens next is each project has a class (TO-DO, DOING, DONE). Each class is one table that has all the project ids that belong to each.
The structure has to be like this, because each class has additional information. And that information only exists if the project belongs to that class. For example, a project in the TO-DO class has a "start_prevision_date" which is only valid in the TO-DO table (fields from other classes are still null).
What I want to do is assign one color to each project depending if he is TO-DO, DOING or DONE. A perfect solution would be a query that return values like:
ResultSet:
+--------------+------------------+-------------------+-------+-------+------+
| country.name | country.latitude | country.longitude | TO-DO | DOING | DONE |
+--------------+------------------+-------------------+-------+-------+------+
| Portugal | 13,4 | 15,6 | 1 | 0 | 0 |
+--------------+------------------+-------------------+-------+-------+------+
Can be in more than one column at once
Where 1 means he belongs and 0 means he doesn't belong. I could just check, and print the right color!
Is there a way to do this efficiently? Avoiding the use of extra three queries.
I hope I was clear.
You can use a query like this:
SELECT
country.name,
country.latitude,
country.longitude,
IF (TO-DO.sureField IS NULL, 0, 1) as TO-DO,
IF (DOING.sureField IS NULL, 0, 1) as DOING,
IF (DONE.sureField IS NULL, 0, 1) as DONE
FROM projects
LEFT JOIN country ON projects.countryid = country.id
LEFT JOIN TO-DO ON projects.projectid = TO-DO.projectid
LEFT JOIN DOING ON projects.projectid = DOING.projectid
LEFT JOIN DONE ON projects.projectid = DONE.projectid;
sureField has to be a field in each class table that is surely populated and not null when a project is in that class and null otherwise.
I tested in MySql reproducing a similar case and it worked.
This will give you:
ResultSet:
+--------------+------------------+-------------------+-------+-------+------+
| country.name | country.latitude | country.longitude | TO-DO | DOING | DONE |
+--------------+------------------+-------------------+-------+-------+------+
| Portugal | 13,4 | 15,6 | 1 | 1 | 0 |
+--------------+------------------+-------------------+-------+-------+------+
If the projects in DOING remain also in TO-DO, or:
ResultSet:
+--------------+------------------+-------------------+-------+-------+------+
| country.name | country.latitude | country.longitude | TO-DO | DOING | DONE |
+--------------+------------------+-------------------+-------+-------+------+
| Portugal | 13,4 | 15,6 | 0 | 1 | 0 |
+--------------+------------------+-------------------+-------+-------+------+
If the projects in DOING are deleted from TO-DO.
Therefore you will have to manage the query on result set appropriately.
Regards

Categories