What I have is 3 tables (starred ids may be null):
ITEMS
id|name|cost
EVENTS
id|name|date|assignment|items
ASSIGNMENTS
id|name|start|items
where ITEMS contains lines of cost - an event may cost X and the assignment/project owning that event may have its own lines of cost. All Items in Events and assignments tables are referenced as comma separated lists of ids.
Given an Assignment, I'd like to get
ASSIGNMENTS.NAME|EVENTS.NAME|ITEMS.NAME|ITEMS.COST
Assignment A management 10.00
Assignment A event A travel exp 60.00
Assignment A event A day cost 100.00
Assignment A event B day cost 90.00
I tried the subquery way, building a subquery that returns a list of Items with
SELECT assignments.name, events.name,
concat(events.items, ",", assignments.items)
FROM assignments left join events
ON find_in_set(events.assignment, assignments.id) where assignments.id=2
but that way I would get the assignment item listed twice and, what's worst, I would get a line (assignment without event) with a field starting with comma.
I also tried joining twice the same table, but then MySQL remembered me that I cannot do it.
Any idea on how to solve this?
try this way
SELECT assignments.name, events.name,
concat(events.items, ",", assignments.items)
FROM assignments left join events
ON events.assignment = assignments.id
where assignments.id=2
Related
I have a query i have been working on trying to get a specific set of data, join the comments in duplicate phone numbers of said data, then join separate tables based on a common field "entry_id" which also happens to be the number on the end of the word custom_ to pull up that table.
table named list and tables containing the values i want to join is custom_entry_id (with entry_id being a field in list in which i need the values of each record to replace the words in order to pull up that specific table) i need entry_id from the beginning part of my query to stick onto the end of the word custom for every value my search returns to get the fields from that custom table designated for that record. so it will have to do some sort of loop i guess? sorry like i said I am at a loss at this point
this is where i am so far:
SELECT * ,
group_concat(comments SEPARATOR '\r\n\r\n') AS comments_combined
FROM list WHERE `status` IN ("SALEA","SALE")
GROUP BY phone_number
//entry_id is included in the * as well as status
// group concat combines the comments if numbers are same
i have also experimented on test data with doing a full outer join which doesnt really exist. i feel if you can solve the other part for me i can do the joining of the data with a query similar to this.
SELECT * FROM test
LEFT JOIN custom_sally ON test.num = custom_sally.num
UNION
SELECT * FROM test
RIGHT JOIN custom_sally ON test.num = custom_sally.num
i would like all of this to appear with every field from my list table in addition to all the fields in the custom_'entry_id' tables for each specific record. I am ok with values being null for records that have different custom fields. so if record 1 has custom fields after the join of hats and trousers and record 2 has socks and shoes i realize that socks and shoes for record 1 will be null and hats and trousers for record 2 will be null.
i am doing all this in phpmyadmin under the SQL tab.
if that is a mistake please advise as well. i am using it because ive only been working with SQl for a few months. from what i read its the rookie tool.
i might be going about this all wrong if so please advise
an example
i query list with my query i get 20,000 rows with columns like status, phone_number, comments, entry_id, name, address, so on.
now i want to join this query with custom fields in another table.
the problem is the custom tables' names are all linked to the entry_id.
so if entry_id is 777 then the custom table fields are custom_777
my database has over 100 custom tables with specials fields for each record depending on its entry_id.
when i query the records I don't know how to join the custom fields that are entry_id specific to the rest of my data.i will pull up some tables and data for a better example
this is the list table:
this is the custom_"entry_id"
Full Outer Join in MySQL
for info on full outer joins.
this is in mysql v. 4.x... i'm sure this is an rookie question but for some reason i can't get figure out the sql to get this to work. here is an approximation of the relevant tables:
Item
---
ItemID
etc.
ItemPerson
--------
PersonID
ItemID
TimeAccessed
Let's say I have Item ID's of 1,2,3,4,5
Let's say that I have 1 record in ItemPerson: {'JohnDoe',1,'12:00PM'}
I have a PersonName as input. I want returned a list of all items, including the time that item was accessed. If that item was not accessed by the given PersonName, I want NULL for the time.
I've tried the following:
SELECT i.*, ip.TimeAccessed
FROM Item i LEFT OUTER JOIN ItemPerson ip
ON i.ItemID = ip.ItemID
WHERE (ip.PersonName = 'JohnDoe' OR ip.PersonName IS NULL)
I get the expected results for 'JohnDoe'... All items are returned and ItemID 1 has a time.
If I change 'JohnDoe' to 'JaneDoe', I only get ItemID's 2-5 but I want my query to return all items, just with NULL for all the times.
LEFT JOINs can be tricky in these circumstances. You'll want to move the person condition into the ON clause; otherwise you are getting the items associated with that person or no one at all. (Logically speaking, optimizer aside, the WHERE occurs after the JOIN).
Setup
I am creating an event listing where users can narrow down results by several filters. Rather than having a table for each filter (i.e. event_category, event_price) I have the following database structure (to make it easy/flexible to add more filters later):
event
event_id title description [etc...]
-------------------------------------------
fllter
filter_id name slug
-----------------------------
1 Category category
2 Price price
filter_item
filter_item_id filter_id name slug
------------------------------------------------
1 1 Music music
2 1 Restaurant restaurant
3 2 High high
4 2 Low low
event_filter_item
event_id filter_item_id
--------------------------
1 1
1 4
2 1
2 3
Goal
I want to query the database and apply the filters that users specify. For example, if a user searches for events in 'Music' (category) priced 'Low' (price) then only one event will show (with event_id = 1).
The URL would look something like:
www.site.com/events?category=music&price=low
So I need to query the database with the filter 'slugs' I receive from the URL.
This is the query I have written to make this work:
SELECT ev.* FROM event ev
WHERE
EXISTS (SELECT * FROM event_filter_item efi
JOIN filter_item fi on fi.filter_item_id = efi.filter_item_id
JOIN filter f on f.filter_id = fi.filter_id
WHERE efi.event_id = ev.event_id AND f.slug = 'category' AND fi.slug ='music')
AND EXISTS (SELECT * FROM event_filter_item efi
JOIN filter_item fi on fi.filter_item_id = efi.filter_item_id
JOIN filter f on f.filter_id = fi.filter_id
WHERE efi.event_id = ev.event_id AND f.slug = 'price' AND fi.slug = 'low')
This query is currently hardcoded but would be dynamically generated in PHP based on what filters and slugs are present in the URL.
And the big question...
Is this a reasonable way to go about this? Does anyone see a problem with having multiple EXISTS() with sub-queries, and those subqueries performing several joins? This query is extremely quick with only a couple records in the database, but what about when there are thousands or tens of thousands?
Any guidance is really appreciated!
Best,
Chris
While EXISTS is just a form of JOIN, MySQL query optimizer is notoriously "stupid" about executing it optimally. In your case, it will probably do a full table scan on the outer table, then execute the correlated subquery for each row, which is bound to scale badly. People often rewrite EXISTS as explicit JOIN for that reason. Or, just use a smarter DBMS.
In addition to that, consider using a composite PK for filter_item, where FK is at the leading edge - InnoDB tables are clustered and you'd want to group items belonging to the same filter physically close together.
BTW, tens of thousands is not a "large" number of rows - to truly test the scalability use tens of millions or more.
I am attempting to determine the total number of people who attended events hosted by a specific group.
I want to display the total number of attendees, the maximum attendance allowed, the event title, event date, and the event contact person. I tried the following query in different ways, but keep getting the "enter paramenter value" dialog box in MS Access 2007. What do I need to change?
SELECT sum(eventAttendance.attended) AS attendanceTotal, events.max, events.title, events.date, events.eventContact, events.unit
FROM (client INNER JOIN eventAttendance ON client.clientID=eventAttendance.clientID) INNER JOIN events ON eventAttendance.ID=events.id
WHERE events.unit='CTL'and eventAttendance.attended = 'yes'
GROUP BY attendanceTotal, events.max, events.title, events.date, events.eventContact, events.unit;
Thank you.
Table Relationships
SELECT
events.[max],
events.title,
events.[date],
events.eventContact,
events.unit,
Count(eventAttendance.attended) AS attendanceTotal
FROM
(client INNER JOIN eventAttendance
ON client.clientID=eventAttendance.clientID)
INNER JOIN events ON eventAttendance.ID=events.id
WHERE
events.unit='CTL'
AND eventAttendance.attended = 'yes'
GROUP BY
events.[max],
events.title,
events.[date],
events.eventContact,
events.unit;
I changed the aggregate function from Sum() to Count(). Notice the aggregate function does not get included in the GROUP BY clause --- the GROUP BY lists only the fields (or field expressions) which determine the groups, NOT any aggregate functions.
I also added square brackets around the field names max and date because those are both reserved words --- bracketing the names reduces the risk of confusing the database engine.
Edit: Your picture which shows the relationships also shows you have additional reserved words as field names. Suggest you download Allen Browne's Database Issue Checker Utility and check your application with it. It will warn you about reserved words and also other potential "gotcha" issues.
I have an application where I'll have repeating events. So an event can repeat by day, "every n days", by week, "every n weeks on Mon/Tue/Wed/etc", and by month, "every n months on the 1st,2nd,3rd,etc".
What is the best way to handle this from a table design perspective? I can think of two ways but I'm not sure which one is better.
1) 5 columns for the above, 1 for the day case and 2 each for week and month. Whichever ones are not being used would be null. In my application I could see the nulls and choose to ignore them.
2) Have a second table, say events_dateinfo or something, against which I'd JOIN for the query.
Seems like option 2 is probably more 'normalized' and what not, but does it strike you as overkill for such a simple thing? Also, if I were to go option 2, is there a way to translate rows into columns - that is, select the 2 week attributes for a specific event and have them treated as columns?
If I understood right event can have more than 1 schedule (this is why you want " to translate rows into columns ").
You will need not 2 but 3 tables in this case; third one must be junction table. You can easily add new schedules if you need in the future with this scheme.
So, something like this:
table events (event_id, event_name, description)
table schedules (sch_id, schedule)
table event_schedule (event_id, sch_id)
There isn't PIVOT possibility in MySQL as I know, but you can use GROUP_CONCAT() function in SELECT; it'll be one row per event and all schedules for one event will be in one column.
SELECT e.event_name AS Event, GROUP_CONCAT( s.schedule SEPARATOR ', ') AS Schedule
FROM events e
(LEFT) JOIN event_schedule es
ON e.event_id = es.event_id
JOIN schedules s
ON s.sch_id = es. sch_id
GROUP BY e.event_name;
I would prefer to handle this normallized, The events in one table, and the event recurrency in another.
Handling the indexes in a appropriate way, you can handle the request for data through views, or if data gets larger, as an audit table with triggers.