showing a grandtotal of values in a field - php

good pm. i was thinking is it possible to show the summation or grand total of a selected field in the table and with relation to date:
for example is i want to know the total beer consumption of my hotel every month.
i have here my table on services:
[services_id[pk],
customer_id[fk],
date_in,date_out,room_type,room_number,
extra_ref,
extra_bed,extra_snack,
extra_beer,extra_softdrinks,
extra_pillows,extra_breakfast,
extra_snack_q,
extra_beer_q,
extra_softdrinks_q,
extra_pillows_q,
extra_breakfast_q]
can you give some advice on how can i get it.
thanks in advance:
-renz

SELECT SUM(beer_amount) as monthly_beer_amount
FROM [DATABASE].[TABLE]
WHERE beer_sold_date BETWEEN '20110201' AND '20110228'
[EXTRA INFO]
Also I believe that the best way to organize this table is to separate out this table into a few other tables. Store customer info in the first table such as
[customer_id, customer_name, date_in, date_out, room_type, room_number].
1, Bob, 20110101, 20110110, big, 200
2, Joe, 20110101, 20110110, small, 202
....
And have another table named something like room_items which would have the following,
[id, item_name]
1, BEER
2, BED
3, SNACK
...
And then another table named room_purchases which will have the following,
[customer_id, purchase_id, amount, date....]
1, 1, 10, 20110101
2, 3, 5, 20110101
3, 1, 9, 20110101
....
This would help you to do a join on all three tables and they would be more normalized in this way.
SELECT SUM(t2.amount) as beer_amount
FROM customers as t1
LEFT JOIN room_purchases as t2 ON t1.customer_id = t2.customer_id
WHERE t2.purchase_id = 1 AND t2.date BETWEEN 20110101 AND 20110131

SELECT DATE_FORMAT(date_in,"%m-%Y") AS month,SUM(extra_beer) AS beers
FROM your_table
GROUP BY month
this will return something like this:
02-2011 | 43
03-2011 | 52
if you want to limit the query depending on the date just add a WHERE constraint before the GROUP BY

Related

JOIN with 2 Tables (Voting) Mysql, PHP

Hello I have 3 Tables but i need only help with 2 Tables.
The first Table is champions. In this Table are over 100 names.
The second Table is champion_names there are nicknames for the first Table.
The third Table is champion_names_vote. There are the votes for the nicknames. Thumb up if I like any nickname or thumb down.
On my website I have a site where I can see a list full of Names (Table 1). There are 2 columns. In the first is the normal name (Table 1) in the second the nickname (Table 2). Now I want to show the best nickname in column 2. Actually it's random but I only want to show the best nickname.
I can show all Names that's not the problem. But if I want to show only the best nicknames I don't know how.
Table 2: id(AI), champ_id(this is the id for Table 1), sender_id, name
Table 3: id(AI), userid, name_id(Table 2 ID), like_dislike
like_dislike = 1 is like, -1 is dislike and 0 is nothing.
Example:
Table 2: 50, 2, 4, Test
Table 3: 1, 3, 50, 1,
I liked the name of Table 2. So the name_id in Table 3 is the id of Table 2
So how can I do this with JOIN?
Can you help me please.
something like this should do the trick.
Idea is to Analyse your votes per nickname first. Then select the Maximum vote-score by HAVING:
SELECT voteResult.name, vote as winnerVoteScore
FROM(
select a.name_id, b.name,
sum(IF(a.like_dislike = 1, 1, IF(a.like_dislike = 2, -1, 0 ))) as vote
FROM champion_names_vote as a JOIN champion_names as b
ON a.name_id = b.ID
GROUP BY 1
) as voteResult
GROUP BY 1
HAVING vote = max(vote)

Getting advanced data from MySQL

I got a table named 'objects, events & events_types', and these tables got a structure (not the all structure of it, but the basic information which I need to display from the database) and some information like this:
Objects:
structure:
id(INT), title(TEXT)...
data:
1, House #1
2, House #2
3, House #3
Events:
structure:
id(INT), object_id(INT), event_type(INT)
data:
1, 1, 3
2, 1, 1
3, 2, 4
4, 2, 5
5, 2, 1
6, 1, 1
7, 2, 2
8, 1, 3
Events_Types:
structure: id(INT), name(VARCHAR)
data:
1, Alarm
2, Dis/Arm
3, Fire
4, Alarm button
5, Unknown
I have a page, which loads all data from events table, but I need the page displays me only those objects from objects table which has a data into events table. It won't load me id(3) object from objects table because there is no row into events table which has object_id 3.
I need a html table with the following columns:
objects.id
objects.title
events_types.name
count from events table where object_id of this table is the id of objects table and event_type from events table is got by $_GET['event_type'] from URL which will be defined as variable
Example of the table with information from database where $_GET['event_type'] = 1 and this '1' from events_types table is Alarm:
| 1 | House #1 | Alarm: 2 |
| 2 | House #2 | Alarm: 1 |
but the House #3 won't be displayed because there is no data for it in the events table.
For the information, in the real table I've got around 200 records in the objects table and around 500 records in the events table every month. It's like a statistic system for me.
From what you're describing, this sounds like a pretty straightforward join:
SELECT
objects.id,
objects.title,
events_types.name
FROM
objects INNER JOIN events on events.object_id = objects.id
INNER JOIN events_types on events_types.id = events.event_type;
This should give you one record for each event, which will be labeled with the name of that event type. Any objects that don't have events associated with them won't show up.
See if this query gets you the data you want:
SELECT O.id AS object_id, O.title, T.name, COUNT(*) as event_count
FROM Objects O
JOIN Events E ON O.id = E.object_id
JOIN Events_Types T ON E.id = T.id
GROUP BY O.id, E.event_type

How to JOIN tables to get all of Table A, and most of Table B

I'm pretty sure I need a LEFT JOIN for this, but I have a snag. I need to pull one column from table B dependant on a column in table A.
TABLE A = list
list_id
user_id
operator_id
operator_name
operator_level
TABLE B = operators
operators_id
type
image
skill1
skill2
skill3
1
2
3
...
10
Here is the SQL Query that I have now:
SELECT * FROM list l
LEFT JOIN operators o ON l.operator_id = o.operators_id
WHERE l.user_id=1
ORDER BY o.10 DESC
It returns all of Table A, which I want, and also returns all of Table B, which I don't need.
The columns 1-10 contain INT values, and those columns correspond to the operator_level in Table A.
So really what I need is to create a temp column, and put whatever INT is in the 1-10 column that corresponds to the operator_level, or only return that column for that row. I have no idea how to do that though.
Here is some sample data, and expected results:
list list_id, user_id, operator_id, operator_name, operator_level
1, 1, 2, Johnson, Bob, 1
2, 1, 3, Mouse, Mickey, 9
3, 1, 2, Duck, Donald, 5
operators operator_id, type, image, skill1, skill2, skill3, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10
1, pilot, image.jpg, F16, B32, , 50, 60, 70, 80, 90, 100, 110, 120, 130, 140
2, medic, image.jpg, first aid, trauma, general surgery, 100, 105, 110, 115, 120, 125, 130, 135, 140, 145
3, kitchen, image.jpg, knife, soup, , 20, 22, 24, 26, 28, 30, 32, 34, 36, 38
Expected Results list_id, user_id, operator_id, operator_name, operator_level, type, image, skill1, skill2, skill3, op_rate
1, 1, 2, Johnson, Bob, 1, pilot, image.jpg, F16, B32, 50
2, 1, 3, Mouse, Mickey, 9, medic, image.jpg, first aid, trauma, general surgery, 140
3, 1, 2, Duck, Donald, 5, kitchen, image.jpg, knife, soup, 28
Sorry, it lined up well in my editor, but lost the alignment. when I pasted.
Added sample data to sqlfiddle, don't know how to add expected results there.
http://sqlfiddle.com/#!2/390d8/1
You have the basics right withe the outer join, but what you can do is limit the fields you select in your query like this:
select
l.list_id,
l.user_id,
l.operator_id,
l.operator_name,
l.operator_level,
`1`+`2`+`3`+...+`10` as opLevel
FROM
list l
LEFT JOIN operators o
ON l.operator_id = o.operators_id
WHERE
l.user_id=1
ORDER BY
o.10 DESC
This is based on the fact that it would seem you have 0 for and or a value for the right operator.
Having said that, why on earth would you have ten fields to store one bit of information? Your table should only have the ONE field called something like "OperatorLevel" and have the value in it - unless I am missing something.
Alternately, you could also use a greatest() function in your query if you have multiple values and you want the highest one:
select
l.list_id,
l.user_id,
l.operator_id,
l.operator_name,
l.operator_level,
greatest(`1`, `2`, ... `10`) as opLevel
FROM
list l
LEFT JOIN operators o
ON l.operator_id = o.operators_id
WHERE
l.user_id=1
ORDER BY
o.10 DESC
Edit: Okay, based on additional information you can use the following (ick ick ick) statement:
select
l.list_id,
l.user_id,
l.operator_id,
l.operator_name,
l.operator_level,
case
when l.operator_level=1 then o.`1`
when l.operator_level=2 then o.`2`
when l.operator_level=3 then o.`3`
// etc etc yuck!
when l.operator_level=10 then o.`10`
end as yicky
FROM
list l
LEFT JOIN operators o
ON l.operator_id = o.operators_id
WHERE
l.user_id=1
ORDER BY
o.10 DESC
Edit 2:
I would very much suggest a data normalisation.
Given what you have as data, it seems that you are duplicating data to all sorts of users. This kinda sounds like a nightmare to update. From what I understand, it seems that there is a pay scale for each "skill" and it goes up based on the level of the operator?
I would make a table with the following structure (assumptions based on user 1):
skill level value
B32 1 25
B32 2 30
.....
B32 10 75
F16 1 25
F16 2 30
...
F16 10 75
Then you could simply perform a link from the "list" table to the "operators" table, and then link to the "grades" table based on data within then.
This would make for a much simpler query.
Having said ALL THAT, I would actually look at normalizing your "operators" table down to skills only. Move the "type" and "image" into the "list" table (and call it users while you are at it).
Now the "operators" table should be renamed to a skillset table with data like this:
userID skill Level
1 F16 4
1 B32 8
2 F_Aid 2
This would allow you to have users with more than 3 skills as well as allowing you to easily record each skill level of the user. They might be a superhero at B32, but only mediocre at F16.
Assuming only one int column has value maybe something like this?
SELECT l.*, COALESCE(1,2,3,4,5,6,7,8,9,10) opLevel
FROM list l
LEFT JOIN operators o ON l.operator_id = o.operators_id
WHERE l.user_id=1
ORDER BY COALESCE(1,2,3,4,5,6,7,8,9,10) DESC

MySQL/PHP storing multiple data points

I am relatively new to programming and databases.
I have a MySQL database with a "sales" table. This table lists all sales in a state (i.e. each record is a particular sale), with fields for sellername, and buyerzip. I would like to have another table "seller" that would include sellername, and also include fields to define the sellers market area by zip code - say 50+ zip codes define a market, and the seller could define multiple markets.
These market areas would be used for future queries: showing all sales in a particular market area.
Where do I start in terms of thinking how to store that "market area" data, and then use it for future queries?
Thanks
Table structure:
Sales table: ID, sellerID, buyerZipcode, amount
Seller table: ID, sellerName
Market table: ID, marketName
SellerMarketLink table: ID, sellerID, marketID
MarketZipCode table: ID, marketID, zipCode
Example data
Encoding the information in the first comment to your question
Market table
1, "Store A, first market"
2, "Store A, second market"
3, "Store B market"
MarketZipCode table
1, 1, 1
2, 1, 2
...
7, 1, 7
8, 1, 8
9, 2, 4
10, 2, 5
...
14, 2, 9
15, 2, 10
16, 3, 1
17, 3, 2
18, 3, 3
19, 3, 8
20, 3, 9
21, 3, 10
22, 3, 11
23, 3, 12
Query
Total sales in a market for each seller. Note that since one zip code can be part of several markets, the total of all values in "Total Sales" can be larger than the sum of all 'amount' values in the Sales table.
select Market.marketName, Seller.sellerName, sum(Sales.amount) as "Total Sales"
from Sales join Seller join SellerMarketLink join Market join MarketZipCode
on (Sales.sellerID = Seller.ID AND Seller.ID = SellerMarketLink.sellerID
AND SellerMarketLink.marketID = Market.ID
AND Market.ID = MarketZipCode.marketID
AND MarketZipCode.zipCode = Sales.buyerZipCode)
group by Market.ID, Market.marketName, Seller.ID, Seller.sellerName
order by Market.marketName, Seller.sellerName
I'm going to make the following assumptions here:
sellers have many markets
A market can span many zipcodes
Only one seller is responsible for a market
Markets can't overlap
Leading to the following structure...
sales table
seller | buyerzip
markets table
market | market_zipcodes_id
zipcodes table
market_id | zipcode
Hope that helps...

MySQL SELECT from array of ids where one is mandatory

I'd like to know the most efficient SQL query for achieving this problem:
Say we have a table with two columns, one storing entry ids (entry_id) and one storing category ids (cat_id):
entry_id cat_id
3 1
3 2
3 3
3 20
4 1
4 2
4 21
I'd like to count how many distinct entry_id's there are in the categories 1, 2 OR 3 but that also must be in cat_id 20.
For example, categories 1, 2 and 3 might represent music genres (Country, Pop etc.), while category 20 might be recording formats (CD, Vinyl etc.). So another way of putting it verbally could be: "How many products are there that are on Vinyl and in either the Pop or Country category?"
I could achieve this with a nested loop in code (PHP) or possibly with a nested SQL subquery, but neither feels that efficient. I feel there must be an obvious answer to this staring me in the face...
EDIT TO ADD:
I would also like to do this without modifying the database design, as it's a third party system.
FURTHER EXAMPLE TO CLARIFY:
Another real-world example of why I'd need this data:
Let's say the category ids instead represent either:
Accommodation Types (Camping = 20, Holiday Cottage = 21)
OR
Continents and their sub-regions (i.e. Europe = 1, UK = 2, England = 3)
Let's say someone has selected that they are interested in camping (cat_id = 1). Now we need to count how many camping products there are in the Europe. A product might be tagged as both Europe (parent), UK (child) AND England (grand-child), giving us an array of category ids 1, 2 or 3. So we now need to count how many distinct products there are in both those categories AND the original accommodation category of 1 (camping).
So having selected Camping, the end result might look something like:
Europe: 4 camping products
UK: 2 camping products
England : 1 camping product
Wales : 1 camping product
France: 2 camping products
etc.
Hope that helps...
I believe you want GROUP BY, COUNT() and EXISTS()
declare #t table(entry_id int, cat_id int)
insert #t select 1, 1
insert #t select 2, 1
insert #t select 1, 2
insert #t select 2, 2
insert #t select 3, 1
insert #t select 1, 20
select t1.cat_id, COUNT(*)
from #t as t1
where exists(
select * from #t
where t1.entry_id = entry_id
and cat_id = 20)
group by t1.cat_id
V2 using join instead of EXISTS()
declare #t table(entry_id int, cat_id int)
insert #t select 1, 1
insert #t select 2, 1
insert #t select 1, 2
insert #t select 2, 2
insert #t select 3, 1
insert #t select 1, 20
select t1.cat_id, COUNT(*)
from #t as t1
join #t as t2 on t1.entry_id = t2.entry_id and t2.cat_id = 20
group by t1.cat_id
select count(distinct entry_id) from myTable where cat_id=20 and entry_id in
(select distinct entry_id from myTable where cat_id in (1,2,3));
With no subqueries, using JOIN and GROUP BY:
Join the table to itself using entry_id (this gives you all possible pairs of cat_id for that entry_id). Select rows having cat_id both a member of (1,2,3) and the second cat_id = 20.
SELECT r1.entry_id
FROM records r1
JOIN records r2 USING(entry_id)
WHERE r1.cat_id IN (1,2,3)
AND r2.cat_id = 20 GROUP BY entry_id;

Categories