I need to generate a HTML Table based on data which comes from MySQL Database. The Table is complicated so i will try to explain it here.
Data:
Article Name, Price, Date
Article1, 100.5, 2014-08-01
Article2, 90.0 , 2014-08-01
Article3, 80.0 , 2014-08-01
Article2, 90.0 , 2014-08-02
Article3, 80.0 , 2014-08-02
Article1, 100.5, 2014-08-03
Article3, 80.0 , 2014-08-03
This are the dataset which i get from Database. For everyday we get an entry of articles and their price. But it can be that an article is not available on a day. In such a case we need to set zero Price for this date. So now i have to build a horizontal table to compare the results. Some thing like this:
Screenshot
Can somebody tell me how I can generate such a table with PHP/HTML?
Your table is violating the first normal form because you have repeating data. Look here: Normal forms
A better way to create the database is to split your table into 2. First you have a table
Article
-----------
ID Article name
and a table
Price
----------------
ID fkArticle Price Date
the fkArticle is called a foreign key and is a link to the Article table. ID is a primary key and should be auto incremented. Both ID and fkArticle are the type 'int'
This is a lot better because you can avoid having a price of 0 if it the price doesn't exist. And you can extract all prices of an article like this
SELECT * FROM Price WHERE fkArticle = 1
This will get you all prices for an article with the ID=1
You can also easily get your first result by searching on date
SELECT * FROM Price INNER JOIN Article ON Article.ID=fkArticle WHERE Date="2014-08-01"
This is a much more flexible way to do it and is adhering to the Normalforms.
Related
I need to summary columns together on each row, like a leaderboard. How it looks:
Name | country | track 1 | track 2 | track 3 | Total
John ENG 32 56 24
Peter POL 45 43 35
Two issues here, I could use the
update 'table' set Total = track 1 + track 2 + track 3
BUT it's not always 3 tracks, anywhere from 3 to 20.
Secound if I don't SUM it in mysql I can not sort it when I present data in HTML/php.
Or is there some other smart way to build leaderboards?
You need to redesign your table to have colums for name, country, track number and data Then instead if having a wide table with just 3 track numbers you have a tall, thin table with each row being the data for a given name, country and track.
Then you can summarise using something like
SELECT
country,
name,
sum(data) as total
FROM trackdata
GROUP BY
name,
country
ORDER BY
sum(data) desc
Take a look here where I have made a SQL fiddle showing this working the way you want it
Depending upon your expected data however you might really be better having a separate table for Country, where each country name only appears once (and also for name maybe). For example, if John is always associated with ENG then you have a repeating group and its better to remove that association from the table above which is really about scores on a track not who is in what country and put that into its own table which is then joined to the track data.
A full solution might have the following tables
**Athlete**
athlete_id
athlete_name
(other data about athletes)
**Country**
country_id
country_name
(other data about countries)
**Track**
Track_id
Track_number
(other data about tracks)
**country_athlete** (this joining table allows for the one to many of one country having many athletes
country_athlete_id
country_id
athlete_id
**Times**
country_athlete_id <--- this identifies a given combination of athlete and country
track_id <--- this identifies the track
data <--- this is where you store the actual time
It can get more complex depending on your data, eg can the same track number appear in different countries? if so then you need another joining table to join one track number to many countries.
Alternatively, even with the poor design of my SQL fiddle example, it might be good to make name,country and track a primary key so that you can only ever have one 'data' value for a given combination of name, country and track. However, this decision, and that of normalising your table into multiple joined tables would be based upon the data you expect to get.
But either way as soon as you say 'I don't know how many tracks there will be' then you should start thinking 'each track's data appears in one ROW and not one COLUMN'.
Like others mentioned, you need to redesign your database. You need an One-To-Many relationship between your Leaderboard table and a new Tracks table. This means that one User can have many Tracks, with each track being represented by a record in the Tracks table.
These two databases should be connected by a foreign key, in this case it could be a user_id field.
The total field in the leaderboard table could be updated every time a new track is inserted or updated, or you could have a query similar to the one you wanted. Here is how such a query could look like:
UPDATE leaderboard SET total = (
SELECT SUM(track) FROM tracks WHERE user_id = leaderboard.user_id
)
I recommend you read about database relationships, here is a link:
https://code.tutsplus.com/articles/sql-for-beginners-part-3-database-relationships--net-8561
I still get a lot of issues with this... I don't think that the issue is the database though, I think it's more they way I pressent the date on the web.
I'm able to get all the data etc. The only thing is my is not filling up the right way.
What I do now is like: "SELECT * FROM `times` NATURAL JOIN `players`
Then <?php foreach... ?>
<tr>
<td> <?php echo $row[playerID];?> </td>
<td> <?php echo $row[Time];?> </td>
....
The thing is it's hard to get sorting, order and SUM all in ones with this static table solution.
I searched around for leaderboards and I really don't understand how they build theres with active order etc. like. https://www.pgatour.com/leaderboard.html
How do they build leaderboards like that? With sorting and everything.
I have a table full of products including price, name, date and ID (PK)
I am in need to update the records when there is a price change (Web scraping script), how would i go about this so that a new row is NOT inserted, rather the price and date are updated.....but the previous values need to remain in the DB....so that when i when i go
"SELECT * FROM items WHERE id ='27'";
Output wanted:
$400 12.4.2013
$314 22.4.2013
$250 12.4.2013
The product will be then displayed with all the updated values since the first price was downloaded, effectively it will be a history of the prices for the item...
the actual results i want to achieve would hopefully be
History for "Product 27" is:
To give more context, when i run my script... ./script.php update
all the new data should be inserted or updated....but old values remain
im not too sure how i should approach this....please provide me with some guidance or assistance
The best way to go about this while keeping a tidy database with easily maintainable and readable data would be to take what #KishorSubedi said in the comment and create a log table.
When you update your price in your Products Table, store the old price, along with its date and ID in the Log Table then when you need to look up all the records for that product you can JOIN the Log Table in your query.
Log Table
| ProductID | Price | Date |
| 27 | $300 | 02.1.2013 |
| 27 | $400 | 03.1.2013 |
This way you can have a nice and neat Products table that is not cluttered with multiples of the same product, and an unobtrusive log table that is easily accessible.
Hope this gives you some guidance on building your site and database.
If you want to keep the old values I would suggest saving them in a seperate table and to use the INSERT statement. You are always adding a new row, so you can not bypass an insert or select into or similar statement.
Table structure:
Items
------------------------------
Id primarykey
Name
Price
------------------------------
Id primarykey autoincrement
ItemId index
AddDate index
Price
Now when you scrape the web you will just insert the new price in the Price table. If you want to select all the prices for an item you can use
SELECT Items.Id
,Items.Name
,Price.Price
,Price.AddDate
FROM Items
LEFT JOIN Price
ON Items.Id=Price.ItemId
WHERE Items.Id='27'
ORDER BY Items.Name ASC, Price.AddDate ASC
And if you just want the latest or current price, you can use
SELECT Items.Id
,Items.Name
,P1.Price
,P1.AddDate
FROM Items
LEFT JOIN Price P1
ON Items.Id=Price.ItemId
LEFT JOIN Price P2
ON P1.ItemId=P2.ItemId
AND P1.Id<P2.Id
WHERE Items.Id='27'
AND P2.Id IS NULL
Add new column for history in 'item' table and each price change append the changed value to this column with a specific format as like date1:price1,date2:price2,....
I am trying to fetch data from multiple tables depending on what is selected in a dropdown menu. My dropdown menu consists of a list of ID's (001, 002, etc).
Once a user selects one of them, I am using AJAX to dynamically fetch data depending on what was selected. I was able to fetch a single value depending on what was selected but having problems when multiple tables are involved.
My tables are set up like this:
Inventory table:
inven_ID (primary)
cost
description
Order table:
order_ID(primary)
orderdesc
Sale table:
inven_ID
order_ID
quantity
primary(inven_ID,order_ID)
My query is as follows:
$QRY = "SELECT
inven_ID,
order_ID,
cost,
description
FROM
Inventory,
Order,
Sale
WHERE Inventory.inven_ID = Sale.inven_id
AND Sale.order_ID = Order.order_ID
AND Order.order_ID ='".$q."'";
The $q represents the value from the dropdown menu (which I checked is valid). I am getting the error Column 'inven_ID' in field list is ambiguous. Basically, when they select some order id from the drop down (say 001), it looks for order_ID in my Order table, and fetches the inven_ID/cost/description of that particular order ID.
Eg. if someone ordered parts xy, yz, xyz for cost 10,20,30.
Selecting 001 would bring up:
001 xy 10
001 yz 20
001 xyz 30
I think I am not joining tables properly since the error says its ambiguous.
Any help on this?
edit: yes that fixed the problem, quite obvious that I did not catch it.
In the column list of your select, you just need to specify which inven_ID you want to retrieve. For instance:
SELECT Inventory.inven_ID, ...
The error is pretty obvious. inven_ID is ambiguous because you have it in Sale and in Inventory. Use a specifier like Sale.inven_ID or Inventory.inven_ID.
I'm looking for for an opinion.
I have a list of people and will need to store when they are present at a location so those in charge can check them off a list. I'm not 100% sure how long the dates will be needed but I'm assuming they may need to look at previous attendance lists.
My first instinct is to have a column for each date but that could result in many many columns. I could just store a list of dates next to each person:
"01/01/2012,01/15/2012,02/18/2012..."
that could result in a very long entry. It seems like neither is a good option.
If anyone has a suggestion or guidance on an approach please let me know. Thanks.
A complex, but also very clean approach would be
Table "persons":
id
name
Table "dates":
id
location
date
... whatever info the "dates" table needs
Table "attendances":
date_id (link to an entry in the "dates" table)
person_id (link to an entry in the "persons" table)
attended (yes/no)
Then fill the database with the appropriate dates, and fill the "attendances" table according to which persons need to be present at each date.
This is, as said, complex to implement, but it's incredibly flexible - you can have any number of dates and attendees; you can excuse people from attending a specific date programmatically; you can add people to groups...
Link tables.
One table of people
ID
Name
One table of classes
ID
Name
One table linking person to class to date.
ID
personID
classID
cDate
So all you would need to do to determine which students were preset on a certain date in a certain class:
SELECT *
FROM people p
LEFT JOIN peopletoclass ptc ON p.id = ptc.personid
LEFT join class c ON c.id = ptc.classid
WHERE ptc.cDate = '2011-11-07' AND c.id = '1';
Above (for example) would get all people in class id 1 on November 7th 2011.
Create a table "attendance" consisting of a person_id field and a date_present field. You can't store this into columns or a long list using a string ;-).
Than you can use queries where you join the table Person with Attendance.
Your first instinct would result in a horrible table design. What you should have is a seperate table that stores the users/locations/dates tuples
e.g.
userID locationID date
1 party 1/1/2011 00:00:00
1 bathroom 1/1/2011 00:05:00
1 party 1/1/2011 00:15:00
would show that user #1 was at a New Year's Eve party, then went to pray before the porcelain altar at 12:05am, then returned to the party 10 minutes later.
I'm working with some imported data that stores details about whether a "room" is available on a specific day or not. Each room has an individual entry for the date that it is available.
| id | date | price |
--------------------------------
| 1 | 2010-08-04 | 45.00 |
A user can search across a date range and the search needs to bring back the relevant rooms that are available between those two dates.
In other words using a sql query to search:
where date>=2010-08-04 AND date<=2010-08-09
would not suffice as this would bring back all rooms available at SOME point between the chosen dates not the rooms that are available for ALL of the dates concerned.
I am considering using a temporary date table in some way to cross-reference that there is an entry for every date in the range but are uncertain as to the best way to implement this.
The end code platform is PHP and I'm also exploring whether the data can be processed subsequently within the code but would like to keep everything with the sql if possible.
Any suggestions that put forward would be greatly appreciated.
Thanks
Update: my original answer was identical to Quassnoi's but 1 minute too late, so I decided to delete it and do something different instead. This query does not assume that (id, date) is unique. If there is more than one entry, it selects the cheapest. Also, it also sums the total cost and returns that too which might also be useful.
SELECT id, SUM(price) FROM (
SELECT id, date, MIN(price) AS price
FROM Table1
GROUP BY id, date) AS T1
WHERE `date` BETWEEN '2010-08-05' AND '2010-08-07'
GROUP BY id
HAVING COUNT(*) = DATEDIFF('2010-08-07','2010-08-05') + 1
Provided that (id, date) combination is unique:
SELECT id
FROM mytable
WHERE date BETWEEN '2010-08-04' AND '2010-08-09'
GROUP BY
id
HAVING COUNT(*) = DATEDIFF('2010-08-09', '2010-08-04') + 1
Make sure you have a UNIQUE constraint on (id, date) and the date is stored as DATE, not DATETIME.