Two Tables & Ordering By Column Not in Both - php

I have two tables.. one for a player's session.. and one for the player's character. I can't change how the tables record data.. so I have to work with these. Ultimately, I am trying to create a "who is online" list and need some help figuring out how to sort it all.
account sessions (if a row is present in this list, account is logged in)
----------------------
| accountid | charid |
----------------------
| 1001 | 2001 |
----------------------
| 1004 | 2006 |
----------------------
| 1002 | 2003 |
----------------------
characters (shows all characters active or not)
------------------------------------
| charid | accountid | charname |
------------------------------------
| 1001 | 2001 | user1 |
------------------------------------
| 1002 | 2001 | user2 |
------------------------------------
| 1003 | 2002 | user3 |
------------------------------------
| 1004 | 2002 | user4 |
------------------------------------
| 1005 | 2003 | user5 |
------------------------------------
| 1006 | 2004 | user6 |
------------------------------------
I'm trying to order by online followed by character name. So according to those tables.. I'd want a printout like this:
ONLINE
user1
user3
user6
OFFLINE
user2
user4
user5
What query do I use to print out data like that when it uses two tables and sorting by the second table character names.. and whether or not they're online- two different sorting from two different tables?
If there were character names in the session table.. it'd make this a whole lot easier.. but I don't think I can change that myself. :( Any help?

Try something like this
SELECT charname, IF(sessions.charid IS NULL, 'offline', 'online') as status
FROM characters
LEFT JOIN sessions
ON characters.charid=sessions.charid
AND characters.accountid=sessions.accountid
ORDER BY status DESC, charname ASC
This should give you a two column table with charname and status, online first.
You could get fancier with the GROUP_CONCAT function too

Related

How to best structure a database while keeping track of dataset changes

I've got a small CRM and I'm trying to figure out the best way to designing the DB tables.
I've currently got a single table for users that got around 30 columns which I alter from time to time. Since I am storing two different information on that table (user + company information) I was thinking of splitting that table into 3 (user + company + connection between these 2) but I am also interested in keeping a copy of any changes that are being made in these rows.
So going from:
user_id | firstname | last_name | company_name | company_city | company_subject | rank | status
1 | John | Borrows | Boink INC | NY | Web dev | 1 | 1
2 | Mike | Smith | Smithin INC | OC | Laywer | 1 | 2
3 | Mary | Anton | Caffin | SJ | Moving | 2 | 1
to something like this
user_id | firstname | last_name | rank | status
1 | John | Borrows | 1 | 1
2 | Mike | Smith | 1 | 2
3 | Mary | Anton | 2 | 1
comp_id | company_name | company_city | company_subject
1 | Boink INC | NY | Web dev
2 | Smithin INC | OC | Laywer
3 | Caffin | SJ | Moving
con_id | user_id | comp_id
1 | 1 | 1
2 | 2 | 2
3 | 3 | 3
But I'm not sure how to track the changes when for example a user changes the company name or some other info on user's table etc.
Just follow the normalization rules for structuring your database tables. You will find anything you need for that by just searching for database normalization.
Regarding your "update-history" you could add a Timestamp to your datasets and/or a separate boolean field "outdated" to be able to filter out the latest information.
Would be the simplest solution that comes into my mind.

Creating a report with more 60000 rows of a vertical table in codeigniter. How to paginate?

A lot of thought process went before I decided to post this question. Trying to explain my problem in a simplified format.
I have 2 tables in my mySQL table, one of which is the users and the other one is the questions and answers related to that user.
Simplified Example:
Users
| id | name | registered_on |
|----|--------|---------------------|
| 1 | Aaron | 2017-02-01 00:01:02 |
| 2 | Baron | 2017-02-01 01:01:02 |
| 3 | Chiron | 2017-02-01 02:01:02 |
Answer Keys
| id | user_id | keyword | value | created_on |
|----|---------|---------|---------|---------------------|
| 1 | 1 | gender | Male | 2017-02-01 00:01:02 |
| 2 | 1 | age | 24 | 2017-02-01 00:01:02 |
| 3 | 2 | gender | Male | 2017-02-01 00:01:02 |
| 4 | 2 | age | Unknown | 2017-02-01 00:01:02 |
| 5 | 3 | gender | God | 2017-02-01 00:01:02 |
I hope the relation above is clear. So what I wish to achieve is to create a CSV report like this
| name | gender | age | registered_on |
|--------|--------|---------|---------------------|
| Aaron | Male | 24 | 2017-02-01 00:01:02 |
| Baron | Male | Unknown | 2017-02-01 01:01:02 |
| Chiron | God | NULL | 2017-02-01 02:01:02 |
As my research suggests, this can be done in the following ways :
Prepared Statements (Cannot use because CodeIgniter does not Support)
Paging (The vertical table is the problem)
MySQL Pivot Tables (But with Dynamic column names -- feels complicated!)
Any other better way that I do not know of
I am thinking about paging but am yet to figure out how it could be
used in the case of vertical tables. I would like it if any of you guys have faced the same problem or have some meaningful suggestions! Any help is appreciated!
If I understand well your problem, you want a CSV file with all user informations available using the answer keys as columns?
Why not doing this with 2 queries?
First, you can select all different keys in your answer table (select distinct keyword...)
Then, create your query with joins looping on your results :
$this->db->select('u.id, u.name, u.registered_on');
$this->db->from('users u');
foreach($keywords as $i_key => $s_keyword){
$this->db->join('answers_table at'.$i_key, 'at'.$i_key.'.user_id = u.id', 'left');
$this->db->select('at'.$i_key.'.value as '.$s_keyword);
}
$a_users = $this->db->get()->result();

Select MySQL return table header as well table body in one query

Hello I am facing hard time trying to realized this task. The problem is that I am not sure in which way this have to be proceeded and couldn't find tutorials or information about realizing this type of task.
The question is I have 2 tables and one connecting table between the two of them. With regular query usually what is displayed is the table header which is known value and them then data. In My case I have to display the table horizontally and vertically since the header value is unknown value.
Here is example of the DB
Clients:
+--------+------ +
| ID | client|
+--------+------ +
| 1 | Sony |
| 2 | Dell |
+--------+------ +
Users:
+--------+---------+------------+
| ID | name | department |
+--------+--------+-------------+
| 1 | John | 1|
| 2 | Dave | 2|
| 3 | Michael| 1|
| 4 | Rich | 3|
+--------+--------+-------------+
Time:
+--------+------+---------------------+------------+
| ID | user | clientid | time | date |
+--------+------+---------------------+------------+
| 1 | 1 | 1 | 01:00:00 | 2017-01-02 |
| 2 | 2 | 2 | 02:00:00 | 2017-01-02 |
| 3 | 1 | 2 | 04:00:00 | 2017-02-02 | -> Result Not Selected since date is different
| 4 | 4 | 1 | 02:00:00 | 2017-01-02 |
| 5 | 1 | 1 | 02:00:00 | 2017-01-02 |
+--------+------+---------------------+------------+
Result Table
+------------+--------+-----------+---------+----------+
| Client | John | Michael | Rich | Dave |
+------------+--------+-----------+---------+----------+
| Sony |3:00:00 | 0 | 2:00:00 | 0 |
+------------+--------+-----------+---------+----------+
| Dell | 0 | 0 | 0 | 2:00:00 |
+------------+--------+-----------+---------+----------+
First table Clients Contains information about clients.
Second table Users Contains information about users
Third Table Time contains rows of time for each users dedicated to different clients from the clients table.
So my goal is to make a SQL Query which will show the Result table. In other words it will select sum of hours which every user have completed for certain client. The number of clients and users is unknown. So first thing that have to be done is Select all users, no matter if they have hours completed or not. After that have to select each client and the sum of hours for each client which was realized for individual user.
The problem is I don't know how to approach this situation. Do I have first to make one query slecting all users then foreach them in the table header and then realize second query selecting the hours and foreaching the body conent, or this can be made with single query which will render the whole table.
The filters for select command are:
WHERE MONTH(`date`) = '$month'
AND YEAR(`date`) ='$year'
AND u.department = '$department'
Selecting single row for tume SUM is:
(SELECT SUM( TIME_TO_SEC( `time` ) ) FROM Time tm
WHERE tm.clientid = c.id AND MONTH(`date`) = '$month' AND YEAR(`date`) ='$year'
This is the query to select the times for a user , here by my logic this might be transformed with GROUP BY c.id (client id), and the problem is that it have to contains another WHERE clause which will specify the USER which is unknown. If the users was known value was for example 5, there is no problem to make 5 subsequent for each user WHERE u.id = 1, 2, 3 etc.
So here are the 2 major problems how to display in same query The users header and them select the sum of hours for each client corresponding the user.
Check out the result table hope to make the things clear.
Any suggestion or answer which can come to resolve this situation will be very helpful.
Thank you!

Mysql auto insert record in primary table if not exist

Is it possible to auto insert a record into the primary table if the record does not exist when adding a foreign key?
For example, assume these tables:
- user(id, name, age)
- topic(id, name)
- post(userId, topicId, text, createdAt, updatedAt)
Now i am pulling posts from some source and saving the records in the post table. But sometimes the data that is being returned contains a userId or a topicId that is not yet in my database. So everytime i would have to check if the user and topic records exist then save if not. Only then my post record would be valid and saved.
I want to be able to save the post even if its related user or topic does not exist, and add an empty row with the in these tables having the ids that have been stored in the post table.
Example:
Current User Table
+----+------+-----+
| id | name | age |
+----+------+-----+
| 15 | Paul | 26 |
+----+------+-----+
| 56 | John | 31 |
+----+------+-----+
current Topic Table
+----+----------+
| id | name |
+----+----------+
| 5 | Business |
+----+----------+
| 12 | General |
+----+----------+
current Post Table:
+--------+---------+----------------+-------------+-------------+
| userId | topicId | text | createdAt | updatedAt |
+--------+---------+----------------+-------------+-------------+
| 15 | 12 | blah blah blah | *timestamp* | *timestamp* |
+--------+---------+----------------+-------------+-------------+
| 56 | 5 | lorem ipsum... | *timestamp* | *timestamp* |
+--------+---------+----------------+-------------+-------------+
So then i fetch post from some sources an get a new 1 This is a new topic posted by a user with id 72 in a topic with id 2. The source only returns the id, and to obtain the rest of the details of the user, i should make another request to their api.
Post Table after:
+--------+---------+---------------------+-------------+-------------+
| userId | topicId | text | createdAt | updatedAt |
+--------+---------+---------------------+-------------+-------------+
| 15 | 12 | blah blah blah | *timestamp* | *timestamp* |
+--------+---------+---------------------+-------------+-------------+
| 56 | 5 | lorem ipsum... | *timestamp* | *timestamp* |
+--------+---------+---------------------+-------------+-------------+
| 72 | 2 | This is a new topic | *timestamp* | *timestamp* |
+--------+---------+---------------------+-------------+-------------+
User Table After:
+----+------+-----+
| id | name | age |
+----+------+-----+
| 15 | Paul | 26 |
+----+------+-----+
| 56 | John | 31 |
+----+------+-----+
| 72 | | |
+----+------+-----+
Topic Table after
+----+------------+
| id | name |
+----+------------+
| 2 | |
+----+------------+
| 5 | Business |
+----+------------+
| 12 | General |
+----+------------+
So now that i have this, i can make my request to their api and look for data for user with id 72 and data for topic with id 2.
People can have strong opinions on this and we can respectfully disagree.
In reference to a comment saying people do this (knowingly loading blank and null junk in tables) all the time as seen in the post Here.
I said:
That reference is a consortium of people out of their minds. Writing a
post saying what people want to hear, putting a lollipop in their
mouths, does not make for a decent answer. In fact, it can be pretty
irresponsible. This OP is doing things in the wrong order. Put stuff
in some staging tables, call the other APIs, get stuff in clean, that
makes me sleep well at night. Referential Integrity has a meaning. We
don't twist it and confuzzle everyone just to please them.
Part of our responsiblity is doing the right thing, in the right order, to keep our data clean and supporting Referential Integrity. And to steer our peers toward the same versus anything contrary. Sort of the Prime Directive.

PHP: Fetching data from *strange* MySQL database

I have a closed-source software written in C#/.NET from a VoIP company which is impossible to customize and wanted to create custom front-end using PHP. I gained access to the database and now see how it functions. I wanted to output the user his 'speed dial' numbers, but having issue solving it. Here are the tables structures:
'customer' table
+-------------------------------------------------------------------------+
| CustomerID | FirstName | LastName | Balance | Email | Password | Status |
|-------------------------------------------------------------------------|
| 1 | Homer | Simpson | 5.00 | h#s.s | iheartm | 1 |
| 2 | Marge | Simpson | 3.00 | m#s.s | ihearth | 1 |
+-------------------------------------------------------------------------+
'calls' table
+------------------------------------------------------------------------+
| CallID | Caller | Callee | ServiceID | Duration | Cost | CustomerID |
|------------------------------------------------------------------------|
| 1 | 1234567 | 7654321 | 30 | 60 | 1.00 | 1 |
| 2 | 7654321 | 1234567 | 45 | 120 | 2.00 | 2 |
+------------------------------------------------------------------------+
'ani' (speed-dial) table
+---------------------------------------+
| PhoneNumber | ServiceID | ContactName |
|---------------------------------------|
| 1234567 | 45 | Homer |
| 7654321 | 30 | Marge |
+---------------------------------------+
As you can see, 1234567 is Homer's phone number and in Marge's speed dial list and 7654321 is Marge's number in Homer's list. Just like I can pull up customer's balance when logged in using: $current_user['Balance'];, is there way to show user his 'speed dial' numbers in PHP?
This request doesn't achieve what you want ?
SELECT
a.CustomerID, a.FirstName, a.LastName, a.Balance, a.Email, a.Status,
b.ServiceID,
(SELECT GROUP_CONCAT(CONCAT(ContactName,':',PhoneNumber)) FROM ani GROUP BY PhoneNumber WHERE ServiceID = b.ServiceID)
FROM customer a
LEFT JOIN calls b ON a.CustomerID = b.CustomerID
WHERE a.CustomerID = 'replace_by_customer_id'
This should fetch the data of the customer table, plus a string that results from concatenating the speed-dial numbers of the customer connected.
I assume that a customerid corresponds to one unique serviceid found in calls, and the serviceid in the table ani indicates the owner of the speed-dial number. But it seems a weird architecture, so you should give us more data or informations about the tables...
There seems to be a missing relation from ServiceID to a specific entry in customer. It would seem strange that the calls table would provide that relation, it should merely use it.
With only the information you supplied you can only join calls to link the CustomerID with the ServiceID which I suppose you have. The query would look like this:
SELECT ContactName, PhoneNumber FROM ani
LEFT JOIN calls ON ani.ServiceID=calls.ServiceID
WHERE calls.CustomerID=xxx

Categories