I have three tables, each contain an auto-incrementing PK. I need to select the latest (ie, ORDERBY DESC) entries from the mix of these tables.
I'd like to do it in one query, with two joins.
My idea was is to somehow select a table, order it by id DESC, then somehow merge the results.
Does anyone have a way (or probably a better idea) of doing this?
(using mysql)
EDIT:
Sorry - here's a more detailed spec:
I have three tables, posts, stories, favs.
Each has (at the least) three columns id, uid and date. They are both PK's. id auto-increments (separately for each table). uid is FK, but that's irrelevant. I need the result set to contain the latest 20 or 30 entries.
UNION with no joins would be a possability.
see http://dev.mysql.com/doc/refman/5.0/en/union.html for details.
Since the tables have no relation, joining them doesn't make any sense, right?
As far as I understood, You would like to order records originating from 3 different tables in one result set by their creation date. There are two ways to achieve this:
Use a PK that is sortable and unique for all 3 tables. I know You can do this easily in PostgreSQL. In MySQL You need a workaround: Create a 4th table with an auto-increment PK and change the other 3 tables PK to a FK pointing at the 4th table PK. This is somewhat cumbersome and You need to be aware of the fact, that an auto-increment field is not a good candidate for a reliably sortable property (deleting records leads to gaps in the sequence, which might be filled later).
Add a column created to each of the 3 tables and store the creation date of each record. The UNION can then be sorted by this column. You already have a column date. Can't You use this column?
Related
I can't figure out what is the better solution.
A table : 35 of fields and 2 of them are longtext type. (Already built-in in the CMS that I'm about to use)
B table : similar amounts of fields and 3 of them are text type.(Newly required data for my project)
At first, I decided to use already existing 'A' table and add new 'B' table. It's far easy way 'cause the CMS already provides the classes and methods (etc - search, crud...) that is needed to my project.
But, my concern is the performance. Since table 'B' is sort of add-on to 'A', most of the DB actions, like showing list, searching, getting contents..., must refer at least those two tables at once each time.
JOIN and multiple queries are absolutely needed. And this site needs to show many lists and contents to online users at same time.
What would be the best solution? Is combining two tables more efficient, or re-using the already-existing codes as much as I can and preserving compatibility to the CMS?
ps. If I combine two tables, I can reduce some of the unnecessary varchar fields in table 'A'.
You only duplicate columns that you will use to relate tableB with tableA. Reasons why you shouldn't duplicate non-primary key columns:
a. table size grows and it's a waste of space if there are duplicate fields between tables.
b. regardless of the column size to be duplicated, it's very laborious maintaining tables just to make sure all duplicate columns are updated correctly. Think for example there's a duplicate column named detail. If you update this column in tableA for a particular id, then you need to make another effort to update the corresponding record in tableB.
c. Will consume lots of effort, resources, time, and money to maintain duplicate non primary key columns between tables.
Combining 2 tables is too expensive and not wise. If those two tables contains duplicate fields, you will waste lots of database space which will impact the CRUD operations. Best approach is to create table B but add only the primary key[s] fields from table A that you can use to link the two tables. In this way it will be easy to retrieve to both tables for data you specifically need. You also don't need to retrieve all data from both tables.
Example:
Table A:
id
fname
lname
.
.
rest of the 35 fields
Table B:
tableb_id
id (from table A)
.
.
rest of table B fields
Your Query:
Select column[s]
From TableA, TableB
Where TableA.id = TableB.id
And (all other conditions like TableA.lname = "Santos");
or use Inner Join
SELECT column_name(s)
FROM tableA INNER JOIN tableB ON tableA.id = tableB.ID
WHERE (all other conditions like TableA.lname = "Santos");
I have the following tables in a database:
products
assembly_steps
parts
warnings
I want to relate the content of these tables as follows:
A product consists of many assembly_steps. An assembly_step can have different part and warnings. So I build the tables
assembly_steps_has_parts
assembly_steps_has_warnings
products_has_assembly_steps
to relate the data. The ...has...-tables are connected with their related partners by foreign keys. I modeled that with the MySQL-Workbench.
I am confused about the mechanism to relate the info. How do I program that in PHP?
I think first you add the content on the lowest level, that would be parts and warnings. Then you add the assembly step and relate the data. But I don't know how to do this.
Here you find an overview: Database-Model
Relational databases relate entities/values by recording them together in a row in a table.
To relate assembly_steps to parts, just insert a row into assembly_steps_has_parts, e.g. if you have the assembly_step_id in $assembly_step_id, and the part_id in $part_id, then:
INSERT INTO assembly_steps_has_parts (assembly_steps_id, parts_id)
VALUES ($assembly_step_id, $part_id)
You wouldn't program this in PHP, you'd handle it fully with mysql. The way this would be structured in mysql would be something like this:
assembly_steps
assembly_id
assembly_description (or something like that
assembly_id is the primary key
parts
part_id
part_name
part_id is the primary key
assembly_steps_has_parts
assemply_id
part_id
In this table, you'd have a dual primary key. Both assembly and part id are foreign keys AND primary keys for their respective tables.
The way that dual primary keys work is that there are two keys to make up one primary key on one table. That means that instead of limiting to 1 key, it limits the table to one of any combination of these keys to make one.
For instance:
pk1 pk2
1 1
1 2
1 3
2 1
2 2
2 3
You could query them like this (this is a generic query, but the basic idea)
select a.assembly_description, p. part_name
from assembly_id a
join assembly_steps_has_parts ats
on a.assembly_id = ats.assembly_id
join parts p
on ats.part_id = p.part_id
You'd do the same thing for the other tables. From that point you'd just call the results of your query in php the way you would handle any other query.
I am writing a complex MySQL query. My actual query is more complex than I mentioned below.
I have a table named example and columns are id, name, option_1, option_2 . Of course id column is PK . I want to retrieve like this:
SELECT `id`,`name`,count(`option_1`),count(`option_2`)
My problem is I want to use "GROUP BY `id`" for count(`option_1`) and "GROUP BY `name`" for count(`option_2`) respectively. Now I have to break down it into multiple code in my php code.
How can I achieve what I want in a single query?
What you're asking for doesn't make a ton of sense. You want option 1 grouped by id and option 2 grouped by name, and you want to show all four columns in one result set.
First of all, if id is a primary key, then the count will just be the number of rows in the table since there will be no duplicate ids.
Second, even if id wasn't a primary key, and there were duplicate values, the grouping is different, so the counts represented in your result set would be grouped incorrectly.
Given that id is a primary key, perhaps your intention is actually to get a total count of the rows in the table. Perhaps this query would suit your needs?
SELECT
name,
COUNT(option_2) AS options
FROM
example
GROUP BY
name
UNION ALL
SELECT
'Total' AS name,
COUNT(*) AS options
FROM
example
This should get you a count of all the option_2 values, grouped by name, with the final row having a name of 'Total' and the count being the total number of rows in the table.
Aside from that, I'm not sure you're going to find the answer you're looking for due to the problems you would encounter matching up groupings.
I have a SQL table with two columns:
'id' int Auto_Increment
instancename varchar
The current 114 rows are ordered alphabetically after instancename.
Now i want to insert a new row that fits into the order.
So say it starts with a 'B', it would be at around id 14 and therefore had to 'push down' all of the rows after id 14. How do i do this?
An SQL table is not inherently ordered! (It is just a set.) You would simply add the new row and view it using something like:
select instancename
from thetable
order by instancename;
I think you're going about this the wrong way. IDs shouldn't be changed. If you have tables that reference these IDs as foreign keys then the DBMS wouldn't let you change them, anyway.
Instead, if you need results from a specific query to be ordered alphabetically, tell SQL to order it for you:
SELECT * FROM table ORDER BY instancename
As an aside, sometimes you want something that can seemingly be a key (read- needs to be unique for each row) but does have to change from time to time (such as something like a SKU in a product table). This should not be the primary key for the same reason (there are undoubtedly other tables that may refer to these entries, each of which would also need to be updated).
Keeping this information distinct will help keep you and everyone else working on the project from going insane.
Try using an over and joining to self.
Update thetable
Set ID = r.ID
From thetable c Join
( Select instancename, Row_Number() Over(Order By instancename) As ID
From CollectionStatus) r On c.instancename= r.instancename
This should update the id column to the ordered number. You may have to disable it's identity first.
I would like to know how to update my database table with new data but having the latest data be at the top with the unique id starting at 1. Here's what I mean:
First insert query, for example, inserts 3 article topics:
id article
1 firstNews
2 secondNews
3 thirdNews
Then the next time I run a Cron job to check for new articles, for example two new articles appear, I want the two new articles to be in the beginning of the table, like this:
id article
1 NewArticle1
2 NewArticle2
3 firstNews
4 secondNews
5 thirdNews
Hope that made sense. This might be a bad way to do it, I guess I could have a column with insert date() and then get the data out OrderBy date but it has to be an easier way to do this. I think this would be the easiest to output the most recent data from the table...
If I do ORDER BY DESC, it would output NewArticle2 before NewArticle1, which would defeat the purpose...
id article
1 firstNews
2 secondNews
3 thirdNews
4 NewArticle1
5 NewArticle2
So by DESC, id 5 would be the first one output...I was really hoping there was a way around this...
You should never do this. Just insert at the end, and to get the latest articles, use a query:
SELECT * FROM articles ORDER BY id DESC;
In general: Don't fit the data to your query, fit the query to your data. The id is not a position or number, it uniquely identifies that row of data.
You could use a Date columns and sort on that. Or just sort by ID descending.
It's rarely a good idea to change a PK in place. Not least, you mah have child tables using that PK and maybe history tables too
Note that there is no implicit order to a SQL table: you always need an ORDER BY to guarantee the resultset order
You should add another column specifically for sorting, e.g. a date. and add an INDEX on it.
Then the query becomes:
SELECT *
FROM news
ORDER BY newsdate DESC
Latest news comes first
If there are two news items that could be posted at exactly the same time, you may wish to include a secondary sort:
ORDER BY newsdate DESC, id ASC
It shouldn't be your concern at all.
ID is not a number nor a position by any means. It's just an unique identifier.
Means every database row sticks to it's id forever. While you want to assign your "unique" id to the every newcoming news, which makes no sense.
So, just have usual autoincremented id and select it using ORDER BY id DESC to have latest entries first.