Actually, I have no idea how does it looks like the question's title, is it exactly related to the issue or not, but I'm gonna try explain my problem:
I have a table named as AdvertClick (that stores the stats of each "Advert" by "AdvertID") and Advert table besides (as you guess the main table that stores my ad lists). So I need to store each advert click data (i.e. "Country","Browser","Language" etc.) in AdvertClick table. For example, the code is below getting top country data from AdvertClick table.
SELECT Count(_ac.ID) AS Click, _ac.Country
FROM `Advert` _a
LEFT JOIN `AdvertClick` _ac ON _ac.AdvertID = _a.ID
WHERE _a.UserID = $UserID
GROUP BY _ac.Country
ORDER BY Click DESC
LIMIT 1
But, I've replicated AdvertClick table as AdvertClick0, AdvertClick1 ... AdvertClick9, because it's (the unique stats table) was getting so heavy and slower. And now, I have 10 tables and all off them are same formed (meaning table colums). I'm just inserting every click data like this;
$TableName = "AdvertClick". $AdvertID % 10;
$SQL = "INSERT INTO ${TableName} ... VALUES (...)";
So, now I want to do same thing above but failing.
I've tried CREATE VIEW in very different ways like;
CREATE ALGORITHM = TEMPTABLE VIEW _tmp_ (colums...) SELECT x,y,z -> fail
CREATE VIEW _tmp_ (colums...) SELECT x,y,z JOIN AdvertClick0 _ac0 -> fail
etc...
Is anyone help me about this (really annoying) issue?
Thanks in advance...
hm... I think view would be appropriate for this kind of situation you should also have a good structured table to get the proper approach on this another approach I would do is to add another column that will identify what type of data are on that row for example:
table: advert
columns: name, country, type
the type will take any value you want or you may create another table and reference it from there as a foreign key to make it more flexible in that case you'll be having only 2 tables. To make if work as a view you can do it this way:
CREATE VIEW 'AdvertClick1' AS SELECT name, country FROM advert WHERE type = 1;
CREATE VIEW 'AdvertClick2' AS SELECT name, country FROM advert WHERE type = 2;
CREATE VIEW 'AdvertClick3' AS SELECT name, country FROM advert WHERE type = 3;
and so on and so forth. :)
i will propose something else entirely.
i think you should keep only one AdvertClick table - DO NOT create many of them and therefore create these other headaches. To get you answers will be even more difficult and even more slow.
Instead, if you are sure you have optimized your queries, you may choose to denormalize selectively to gather your common statistics.
for example:
create an ON INSERT trigger on the single AdvertClick table that increments the count value in a new AdvertClickByCountry table for the current Country. Also, create an ON DELETE trigger that decrements that count for the country.
Then your query above would be trivial - something like:
SELECT click_count, country
from AdvertClickByCountry
ORDER BY Click_count DESC
LIMIT 1
Related
I need the least expensive way to check if my url slug is formed from the values from two separate columns from two separate tables.
I will use dummy example with stores and locations to make this more human readable.
I have the following url:
www.domain.com/store-location
This could be, for example:
www.domain.com/three-words-store-chicago or
www.domain.com/nicestore-new-york-or-some-neighbourhood-with-more-words or
www.domain.com/oneword-oneword
(you get the idea)
Stores are located in table called stores, and locations in the table called locations.
All the combinations are possible in theory.
So, I would need some clever mysql query combined with php which will check if my slug (what goes after .com/) is the exact combination of store+location. So, to make it more descriptive:
url: www.domain.com/cool-store-los-angeles
Check is there "cool-store" in the table stores.slug_stores and is there "los-angeles" in the table locations.slug_location. The number of words of both is undefined as you can see above, so I don't have any possible delimiter.
IT MUST BE THE LEAST EXPENSIVE WAY because both tables tables have around 1000 lines. PLEASE HELP AND THANK YOU GUYS!
ps. IMPORTANT: I MUSTN'T CHANGE URLS IN ANY WAY
Edit: This is real project, website. Depending on the url i.e. slug I return some view with data. So I need to check for www.domain.com/nicestore-nicecity if Nicestore and Nicecity exist in tables stores and locations, and if not, or if anything else is there like www.domain.com/nicestore-nicecityBLABLA to kill that page with 404. Otherwise, if there is Nicestore and Nicecity to return some page populated with related data. I tried so far to make separate table with formed slugs like "nicestore-nicecity" and to use it for queries "SELECT whatever FROM slugs WHERE whatever = 'nicestore-nicecity' and if there is line return whatever I need to show the page ... Simplified... But, this separate table is hard to maintain. If nicestore moves to uglycity, or if it changes name, or if you add a new store or new city. I hope I was more clear now ;-)
I'm assuming that you don't have any id values on which to JOIN your tables, and that you don't have the ability to create such values. In that case, since your store/location combination could be as short as oneword-oneword, the first and last words of the slug are about as much as you can search on. You can extract the start and end parts of the slug using SUBSTRING_INDEX and use that to narrow the set of matches in each table before you try and compare the whole string. In my example, I'm using an SQL variable to store the slug:
SET #store = 'cool-store-los-angeles'
SELECT *
FROM (SELECT *
FROM stores
WHERE store LIKE CONCAT(SUBSTRING_INDEX(#store, '-', 1), '%')) s
JOIN (SELECT *
FROM locations
WHERE location LIKE CONCAT('%', SUBSTRING_INDEX(#store, '-', -1))) l
WHERE CONCAT(s.store, '-', l.location) = #store
This will return all data associated with cool-store-los-angeles assuming that such a store exists.
Demo on dbfiddle
Here's what I know about your system...
You have a stores table with column slug_stores
You have a locations table with column slug_location
I'm going to assume that each table has an id column of some type. I'm also going to assume they have a many-to-many relationship using a third junction table, something like
CREATE TABLE store_locations (
store_id <type>,
location_id <type>,
PRIMARY KEY (store_id, location_id),
FOREIGN KEY (store_id) REFERENCES stores(id),
FOREIGN KEY (location_id) REFERENCES locations(id)
);
If you don't have this sort of relationship defined, I really don't know how you maintain your store locations.
What I would suggest is creating a VIEW to calculate and represent your URLs. For example...
CREATE VIEW store_location_urls AS
SELECT
sl.store_id,
sl.location_id,
CONCAT_WS('-', s.slug_stores, l.slug_location) AS slug
FROM store_locations sl
INNER JOIN stores s ON sl.store_id = s.id
INNER JOIN locations l ON sl.location_id = l.id;
Now you can use this view to do the following...
Check if a request URL slug is valid
SELECT store_id, location_id FROM store_location_urls WHERE slug = ?
If this returns a record, you can then further query the stores and locations tables for whatever extra data you need to render your page (or even just join them in the original query). Otherwise, use
http_response_code(404);
Get all the URL slugs for a particular store
SELECT slug FROM store_location_urls WHERE store_id = ?
Similarly, you could get all the URL slugs for a particular location
An extra note... due to concatenating strings, any indexes you have on stores.slug_stores and locations.slug_location will be useless with the above VIEW. The alternative is to use a real derived table (like what you currently have) and maintain it with triggers.
I think you can query like following in mysql and if do check in php afterwards. From your description, it doesn't sound like there is any join possible between those tables so, union is required, i think.
select col1,col2 from stores where slug_stores = ?
union
select col1,col2 from locations where slug_location = ?
I'm hoping someone may be able to provide some advice regarding a database schema I have created and a SELECT statement that I am using to query the database.
I am attempting to create a database of very old newspaper articles from the 1800's, storing such things as the date, title and full text of the article, an image of the article, the name of the newspaper the article came from, names of locations mentioned in the article and individuals mentioned within the article.
Basically below is the current structure I've created with tbArticle being the main table focus ("test" is the name of the database). I've normalised the name of the newspaper, image info, location info and individuals into their own tables and because it is assumed there will be many articles to many individuals, I've added a link table (lktbArticleIndividuals) of sorts between tbArticle & tbIndividual;
The reason for creating the database is to obviously make a focused set of newspaper articles searchable and store them in a logical format.
My issue or question is this ...
All I want to do is display a list of all the articles in the database, obviously including data from the other tables other than tbArticle and to do this I am using this SELECT query;
SELECT *
FROM tbArticle a
, tbLocation l
, tbNewspapers n
, tbIndividual i
, lktbArticleIndividuals ai
, tbImage m
WHERE a.idLocation = l.idLocation
and a.idNewspaper = n.idNewspaper
and a.idArticle = ai.idArticle
and ai.idIndividual = i.idIndividual
and a.idImage = m.idImage;
Which does what I want ... except ... if more than one individual is listed as being in an article, then two (or more) instances of the whole article are returned with the only difference being the different individual's names being displayed.
If possible, I want to just list each article ONCE, but iterate through the two or more individuals to include them. Can this be done?
If I were to query the database in say PHP I suspect what I might have to do is some sort of loop within a loop to achieve the results I want, but this doesn't seem very efficient to me!!
Does any of this make sense to anyone?!
Instead of SELECT *, you could name the columns you're interested in, and for things such as individuals, use GROUP_CONCAT() to add them all into one field, and at the end of your query, use GROUP BY a.idArticle to limit each article to one row per article.
Assuming you just want the first_name of each individual you could use a group by with a GROUP_CONCAT.
SELECT *,
GROUP_CONCAT(i.firstname)
FROM tbArticle a
, tbLocation l
, tbNewspapers n
, tbIndividual i
, lktbArticleIndividuals ai
, tbImage m
WHERE a.idLocation = l.idLocation
and a.idNewspaper = n.idNewspaper
and a.idArticle = ai.idArticle
and ai.idIndividual = i.idIndividual
and a.idImage = m.idImage;
GROUP BY a.idArticle
However, if you want to get many details of each individual I would encourage you to do two separate queries: one for the articles and another one to get the individuals of each article.
I have a table in MySQL that I'm accessing from PHP. For example, let's have a table named THINGS:
things.ID - int primary key
things.name - varchar
things.owner_ID - int for joining with another table
My select statement to get what I need might look like:
SELECT * FROM things WHERE owner_ID = 99;
Pretty straightforward. Now, I'd like users to be able to specify a completely arbitrary order for the items returned from this query. The list will be displayed, they can then click an "up" or "down" button next to a row and have it moved up or down the list, or possibly a drag-and-drop operation to move it to anywhere else. I'd like this order to be saved in the database (same or other table). The custom order would be unique for the set of rows for each owner_ID.
I've searched for ways to provide this ordering without luck. I've thought of a few ways to implement this, but help me fill in the final option:
Add an INT column and set it's value to whatever I need to get rows
returned in my order. This presents the problem of scanning
row-by-row to find the insertion point, and possibly needing to
update the preceding/following rows sort column.
Having a "next" and "previous" column, implementing a linked list.
Once I find my place, I'll just have to update max 2 rows to insert
the row. But this requires scanning for the location from row #1.
Some SQL/relational DB trick I'm unaware of...
I'm looking for an answer to #3 because it may be out there, who knows. Plus, I'd like to offload as much as I can on the database.
From what I've read you need a new table containing the ordering of each user, say it's called *user_orderings*.
This table should contain the user ID, the position of the thing and the ID of the thing. The (user_id, thing_id) should be the PK. This way you need to update this table every time but you can get the things for a user in the order he/she wants using ORDER BY on the user_orderings table and joining it with the things table. It should work.
The simplest expression of an ordered list is: 3,1,2,4. We can store this as a string in the parent table; so if our table is photos with the foreign key profile_id, we'd place our photo order in profiles.photo_order. We can then consider this field in our order by clause by utilizing the find_in_set() function. This requires either two queries or a join. I use two queries but the join is more interesting, so here it is:
select photos.photo_id, photos.caption
from photos
join profiles on profiles.profile_id = photos.profile_id
where photos.profile_id = 1
order by find_in_set(photos.photo_id, profiles.photo_order);
Note that you would probably not want to use find_in_set() in a where clause due to performance implications, but in an order by clause, there are few enough results to make this fast.
EDIT:Well I guess I should asked then before this question, would it be better to have a database full of tables(college names) that stores numbers than can be sorted in ascending order, or have a database with one table and select all the rows with the same "college name" and then sort the data from those rows after?
"
Is it possible to add a table in a database like...
CREATE TABLE table_name
(
column_name1 data_type,
column_name2 data_type,
column_name3 data_type,
....
)
...but call from a webpage instead of adding a table through mysql? So make a table in a database from code on my website?"
Yes you can send SQL queries through PHP.
Here is a resource that shows just what you're looking for I think
PHP MySQL Create Database and Tables
edit:
It depends on what you're doing, but I agree with the above comments that creating a table on page view is in most cases the wrong move.
If they all have the same basic structure I would put them all in the same table, and you can index the "college name" column. Reading from the database even with many many rows will still be quick, and if you decide to change something later you won't have to change X amount of tables.
You can also retrieve sorted results
SELECT * FROM Colleges WHERE name = 'University of Wisconsin' ORDER BY student_count ASC
My application has a facebook-like stream that displays updates of various types. So it will show regular posts (from the "posts" table), and events (from the "events" tables) table and so on.
The problem is I have no idea how to fetch these records from different tables since they have different columns. Shall I query the database multiple times and then organize the data in PHP? if so, how? I'm not sure how I should approach this.
Your help is much appreciated :)
Unless the events and post are related to each other, then you'd probably query them separately, even if they show up on the same page.
You're not going to want to use JOIN just for the sake of it. Only if there is a foreign key relationship. If you don't know what that is, then you don't have one.
If the data tables are related to each other you can generally get the data back in a single query using some combination of JOINs and UNIONs. For a better answer, however, you'll have to post the structure of your data tables and a sample of what (combined) records you need for the website.
If you don't know the columns, you can get the table meta-data and find out what the columns represent and their corresponding data types.
If you know which columns, you can select from the multiple tables or even use nested selects or joins to get the data out.
Ideally you'd simply use a JOIN to obtain data from multiple tables in one query. However, without knowing more about your table schemas it's hard to provide any useful specifics. (It most likely won't be possible unless you've factored this in from the beginning that said.)
As such, you might also want to create a generic "meta" table that provides information for each of the posts/events in a common format, and provides a means to link to the relevant table. (i.e.: It would contain the "parent" type and ID.) You could then use this meta table as the source for the "updates" stream and drill down to the approriate content as required.
Join the tables on user_id i.e.
Select * from posts p
left join status_updates su on p.user_id = su.user_id
limit 25;
or if your tables differ too much then play with a temporary table first
create table tmp_updates
(
select user_id, p.id as update_id, 'post' as update_type, p.text from posts;
);
insert into table tmp_updates
(
select user_id, su.id as update_id, 'status' as update_type, su.text from status_updates;
);
Select * from tmp_updates
where user_id = '...'
limit 25;