Selecting alternating records from two tables - php

I have two tables in my database: events_users and events_admins. The two are nearly identical (except for a few fields). Both tables also have a promoted field (1 or 0).
+-----------------+-----------------------+-------------------+-------------------+
| events_users_id | events_users_promoted | events_users_name | events_users_date |
+-----------------+-----------------------+-------------------+-------------------+
| 1 | 0 | Users foo | 2012-11-15 |
| 2 | 1 | Users bar | 2012-11-15 |
| 3 | 0 | Users foobar | 2012-11-14 |
+-----------------+-----------------------+-------------------+-------------------+
+------------------+------------------------+--------------------+--------------------+
| events_admins_id | events_admins_promoted | events_admins_name | events_admins_date |
+------------------+------------------------+--------------------+--------------------+
| 1 | 0 | admins foo | 2012-11-14 |
| 2 | 0 | admins bar | 2012-11-15 |
| 3 | 1 | admins foobar | 2012-11-16 |
+------------------+------------------------+--------------------+--------------------+
I cannot put both types of events in one table for various reasons. However, I do want one result, as follows:
All events are ordered by date, most recent first, however an admin event comes first and always alternates with a user event (alternating every record). Promoted user AND admin events are shown first.
+------------------+-----------------------+-------------------+-------------------+
| a 3 | 1 | admins foobar | 2012-11-16 |
| u 2 | 1 | Users bar | 2012-11-15 |
| a 1 | 0 | admins foo | 2012-11-14 |
| u 3 | 0 | Users foobar | 2012-11-14 |
| a 2 | 0 | admins bar | 2012-11-15 |
| u 1 | 0 | Users foo | 2012-11-15 |
+------------------+-----------------------+-------------------+-------------------+
I was wondering if I could do this with one query, using UNION to merge the two tables (the few missing fields in the one table, I'll mark as null), however, I wouldn't know how to sort them. The only way out I see at the moment is using two different queries with a simple ORDER BY promoted DESC, date ASC, put the results in two arrays and merge them alternating with PHP.
EDIT: It seems I haven't explained my goal well enough, as the two current answers don't exactly solve my problem.
The suggested queries first give me all promoted events from one category, then all promoted events of the other type, the normal events of the one type and at last the remaining events of the other type. However, these need to alternate as well: one user promoted, one admin promoted, one user promoted, one admin promoted.... When I've run out of admin promoted events, I want one admin event, one user event, one admin event...

SELECT * FROM (
SELECT
'u' AS TYPE,
id ,
events_users_id AS events_users_id,
events_users_promoted AS promoted,
events_users_name AS name,
events_users_date AS date
FROM eventusers
UNION ALL
SELECT
'a' AS TYPE,
id,
events_admin_id AS events_admins_id,
events_admin_promoted AS promoted,
events_admin_name AS name,
events_admin_date AS date
FROM eventadmins
) AS tmp
ORDER BY ID, TYPE DESC
Check out this http://www.sqlfiddle.com/#!2/5b9a5/10
One more column added to both the tables.
CREATE TABLE `eventusers` (
`id` INT(10) NOT NULL AUTO_INCREMENT,
`events_users_id` INT(10),
`events_users_promoted` INT(10),
`events_users_name` varchar(50),
`events_users_date` date,
PRIMARY KEY (`id`)
);
CREATE TABLE `eventadmins` (
`id` INT(10) NOT NULL AUTO_INCREMENT,
`events_admin_id` INT(10),
`events_admin_promoted` INT(10),
`events_admin_name` varchar(50),
`events_admin_date` date,
PRIMARY KEY (`id`)
);

Related

php, mysql join table columns with another table rows

I have issue getting results from two database table. here is what i have:
table A: 'courses'
math | history | geography | computer
1 | 2 | 3 | 4
and Table B
user_id | classroom_id | course
1 | 5 | 3
1 | 5 | 4
1 | 6 | 2
I returned the table A on a for each loop but I would like to check what courses the user 1 has to return true or false on any Table a columns.
Any help appreciated.
I need help not negative votes :(
You have your database set up wrong I believe. What you want is something like
Table_A:
PKEY | Course
1 | Math
2 | History
3 | Geography
4 | Computer
Table_B:
user_id | classroom_id | course
1 | 5 | 3
1 | 5 | 4
1 | 6 | 2
Then you could do something like
SELECT
TableA.PKEY,
TableA.Course,
TableB.user_id,
TableB.classroom_id,
TableB.course,
FROM TableA
LEFT JOIN TableB
ON TableA.PKEY = TableB.course
^^This will return the data from BOTH tables.
you see this line
ON TableA.PKEY = TableB.course
^^This is called the foreign key.
BIG GOTCHA: Make SURE that the columns for both of those ^^^ are set up EXACTLY the same. For instance, IF TableA.PKEY is an UNSIGNED INT(10), then TableB.course MUST also be UNSIGNED INT(10). They have to be identical for the join to work correctly.

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

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

Select All Fields From Only Latest Created Record of dataset in MySQL?

I am doing a comments table, and I can't quite figure out this query. These comments will be under a particular data record in this application, which is what comment_number refers to. When a comment is created, it is assigned that records 'comment number'.. The comment number + date_added identify each particular comment. If a comment is updated/edited, instead of updating the record itself, it creates another entry in the table with the same comment_number and date_added, and creates a new date_modified. This is due to compliance issues. I have to be able to go back in that particular comment's history.
Here is the table description:
+----------------+---------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+--------------- +---------------+------+-----+---------+-------+
| comment_number | varchar(64) | YES | | NULL | |
| comment | varchar(2048) | YES | | NULL | |
| date_added | datetime | YES | | NULL | |
| date_modified | datetime | YES | | NULL | |
| is_deleted | tinyint(1) | YES | | NULL | |
| date_deleted | datetime | YES | | NULL | |
+--------------- +---------------+------+-----+---------+-------+
So different comments will have the same comment number, but will have different 'date_added' fields. And a particular comment's different versions in history will have the same 'comment_number' and 'date_added' value, but different 'date_modified' fields.
So i need to pull all the fields of the latest modified versions of all comments. I have been playing around with MAX() functions, as well as GROUP BYs, but i have not been able to get the correct results yet.
Any help would be greatly appreciated.
To get the most recent date_modified for every comment, you need a query like this:
SELECT
comment_number,
date_added,
MAX(date_edited) AS max_date_edited
FROM
tablename
GROUP BY
comment_number,
date_added
to get the latest version of the comment, you then need to join the result of this query back:
SELECT c.*
FROM
table_name c INNER JOIN (
SELECT
comment_number,
date_added,
MAX(date_edited) AS max_date_edited
FROM
tablename
GROUP BY
comment_number,
date_added
) m ON c.comment_number=m.comment_number
AND c.date_edited = m.max_date_edited
You could use ORDER BY date_modified in your query, and then set the LIMIT to 1. Decide whether you need ASC (low to high) or DESC (high to low) to get the desired field as the first result.

Database relationship between two databases

I want to create a little blog system. Under each article should be a comment function. I think, I need 2 Databases (1x for the normal articles, 1x for the comments of ech article). Now I dont now how i can create a relationship between boths databases. Here is a picture:
On this picture are the attributes of each database. And how can i contact the databases then? (write & read)
make for every type you want a table. i.e one for articles, writers, categorys etc.
Table articles
+----+-----------+-------+------------+---------+-------------+
| id | writer_id | title | date | message | category_id |
+----+-----------+-------+------------+---------+-------------+
| 1 | 12 | foo | 2015-01-26 | text | 34 |
| 2 | 12 | bar | 2015-01-27 | bar | 32 |
+----+-----------+-------+------------+---------+-------------+
table writer and so on
+-----------+------+
| writer_id | name |
+-----------+------+
| 12 | test |
+-----------+------+
Table comments
+------------+------------+---------+------+
| comment_id | article_id | comment | date |
+------------+------------+---------+------+
and so on
afterwards you can connect them in your sql
SELECT
`articles`.`title`,
`writer`.`name`,
`comments`.`comment`
FROM
`articles`
LEFT JOIN `writer` ON (`writer`.`writer_id` = `articles`.`writer_id`)
LEFT JOIN `comments` ON (`comments`.`article_id` = `articles`.`id`)
Have a look at http://www.codeproject.com/Articles/33052/Visual-Representation-of-SQL-Joins for a visual explanation of joins.
You need two tables in the same database and you can connect them with a foreign key.
ARTICLE (ID_ARTICLE,WRITER,TITLE,DATE,MESSAGE....)
COMMENT (ID_COMMENT,FK_ARTICLE(to know the article), COMMENT_WRITER ... )

MySQL Insert or Replace

I wanted to create a system to track the progress of a player in a game. Each player can be a member of multiple groups, which all have other requirements. In order to track his progress, the stats of the player will be saved once he joins a group. Every time he reloads his stats, the current ones should be saved inside the database.
All stats of the player are stored in a json-format, which will then be parsed either by PHP or JS. An entry with compare = 0 is set once the player joins a group. An entry with compare = 1 should be created the first time a player clicks on Update Stats and from then on it should only be updated, not newly created.
Now my question is: How to achieve that? When reading through the syntax of INSERT INTO I got the following:
INSERT INTO `groups` (`grp`, `id`, `json`, `compare`) VALUES
($grp, $id, $json, 1) ON DUPLICATE KEY SET `json` = $json
However, since there is no key set, and I don't know if I can set up two/three keys (as there can be multiple groups per user, as well as the compare = 0 entry in the same group), I don't think I can do it this way.
+------+----+---------+---------+
| grp | id | json | compare |
+------+----+---------+---------+
| 1 | 1 | stats | 0 |
| 1 | 1 | stats | 1 |
| 1 | 2 | stats | 0 |
| 1 | 2 | stats | 1 |
| 2 | 2 | stats | 0 |
| 2 | 3 | stats | 0 |
| 2 | 3 | stats | 1 |
| 2 | 4 | stats | 0 |
| 2 | 5 | stats | 0 |
+------+----+---------+---------+
grp is the group of the player. There is no real limit set to the
number of groups a player can be in.
id is the ID of the player.
json contains the stats of the player in a json
format (number of points, etc).
compare is a boolean. 0 stands for entry stats (the number of points a player
already had when he registered) and 1 stands for the current stats - Which will
be compared to the entry stats, in order to get the difference (= the points a
player made since joining the group).
I hope my explanation was understandable and someone can help me out.
You can use insert raplace:
REPLACE INTO groups (`grp`, `id`, `json`, `compare`) VALUES (...);
But you must have primary key in table. Replace into automaticly finds out primary key and if record exists, it update row, but if doesn't, it add new row.
You can create a unique key with multiple columns. This will trigger the 'on duplicate' clause.
ALTER TABLE groups
ADD UNIQUE (grp, id, compare)

Categories