MS-Access 2010 DELETE Query LEFT JOIN - ms-access

There's a lot of these issues floating around the net with many solutions, but I'm really struggling with this one.
I have a table [BaseHrs] which looks a little like this -
p_ID b_Person WeekNos HrsRequired
1 A 2016-39 10
1 A 2016-40 10
1 A 2016-41 10
1 A 2016-42 10
1 B 2016-39 11
1 B 2016-40 11
1 B 2016-41 12
1 B 2016-42 09
The table continues with different p_ID, people & week numbers. There is no Primary Key and no indexing. This table also has no relationship with any other table.
It is populated from a Query connected to another table as well as a form for the [HrsRequired] field.
Scenario -
Project 1 (p_ID=1) has now been brought forward by two weeks and BaseHrs table no longer needs row for [WeekNos] 2016-41 & 2016-42.
I initially use a query to show which weeks the project is now running on (qry_SelectNewDates).
I have started my delete query by first creating a Select query which looks like this -
SELECT BaseHrs.*
FROM BaseHrs
LEFT JOIN qry_SelectNewDates
ON BaseHrs.WeekNos = qry_SelectNewDates.WeekNos
WHERE (((BaseHrs.p_ID)=[Forms]![frm_Projects]![p_ID])
AND ((BaseHrs.WeekNos) Not In ([qry_SelectNewDates].[WeekNos])));
This works as intended.
Converting that into a delete query produces an error though. Delete Query -
DELETE BaseHrs.*, BaseHrs.p_ID, BaseHrs.WeekNos
FROM BaseHrs
LEFT JOIN qry_SelectNewDates
ON BaseHrs.WeekNos = qry_SelectNewDates.WeekNos
WHERE (((BaseHrs.p_ID)=[Forms]![frm_Projects]![p_ID])
AND ((BaseHrs.WeekNos) Not In ([qry_SelectNewDates].[WeekNos])));
Error message -
Could not delete from specified tables.
I realise that there is often an issue when trying to delete records in this way. I've tried using it with just 'DELETE.*' in the first line without luck.
I have also made an attempt at a nested Query, but I just can't figure out how to construct it. Any guidance?
**********EDIT**********
With advice from #SunKnight0 I have added a primary key to my BaseHrs table and got this query -
DELETE *
FROM BaseHrs
WHERE b_pKey IN
(SELECT BaseHrs.b_pKey
FROM BaseHrs
LEFT JOIN qry_SelectNewDates
ON (BaseHrs.WeekNos = qry_SelectNewDates.WeekNos)
WHERE (((BaseHrs.p_ID)=[Forms]![frm_Projects]![p_ID])
AND ((BaseHrs.WeekNos) Not In ([qry_SelectNewDates].[WeekNos]))));
This query appears to work but takes a huge amount of time to run. Is that as good as it gets?

Related

Joins are coming back with no rows selected

i'm having some trouble with trying to extract some data from several MySQL tables in a join statement.
My tables and attributes are:
appointment_end_time (table)
appointment_end_time_id (int)(pk)(ai)
appointment_end_date (datetime)
appointment_start_time (table)
appointment_date_id (int)(pk)(ai)
appointment_start_date (datetime)
instructor(table)
instructor_id (int)(pk)(ai)
firstname varchar(45)
lastname varchar(45)
appointment_timetable
appointment_timetable_id int(11) AI PK
instructor_id int(11) FK
appointment_date_id int(11) FK
appointment_end_time_id int(11) FK
SELECT a.appointment_timetable_id, i.instructor_id, ad.appointment_start_date, aet.appointment_end_date
FROM db12405956.appointment_timetable a
JOIN instructor i on i.instructor_id = a.instructor_id
JOIN appointment_start_time ad on ad.appointment_date_id = a.appointment_date_id
JOIN appointment_end_time aet on aet.appointment_end_time_id = a.appointment_end_time_id
ORDER BY a.appointment_timetable_id;
However, this code brings back no rows selected when executed so i'm wondering what i'm doing wrong, any help will be much appreciated
Sample rows:
(appointment_end_time)
appointment_end_time_id appointment_end_date
1 2016-12-26 14:00:00
2 2016-12-24 13:00:00
3 2016-12-26 13:00:00
(appointment_start_time)
appointment_date_id appointment_start_date
1 2016-12-26 15:00:00
2 2016-12-24 16:00:00
3 2016-12-26 15:30:00
instructor_id firstname lastname
1 Sasha Thompson
2 Laura Robinson
3 John Walters
appointment_timetable
appointment_timetable_id instructor_id appointment_date_id appointment_end_time_
1 Blank Blank Blank
2 Blank Blank Blank
3 Blank Blank Blank
What you need is to learn how to diagnose the problem yourself. It is a common problem that a query doesn't return the expected results and you should understand how to break things down to find the issue.
Let's start with your query:
SELECT a.appointment_timetable_id, i.instructor_id, ad.appointment_start_date, aet.appointment_end_date
FROM db12405956.appointment_timetable a
JOIN instructor i on i.instructor_id = a.instructor_id
JOIN appointment_start_time ad on ad.appointment_date_id = a.appointment_date_id
JOIN appointment_end_time aet on aet.appointment_end_time_id = a.appointment_end_time_id
ORDER BY a.appointment_timetable_id;
What you do to break it down is start with the first table and then add the joins (and where conditions although you don't have any here), one at a time until the data problem appears. I find this easiest to do by using select * or select top 1 * (Or top 10 as I usually prefer to see more than one record) instead of the field list because then you don't have to look for the fields that are associated with joins you haven't added in yet.
So start with
SELECT top 10 *
FROM db12405956.appointment_timetable a
Then try
SELECT top 10 *
FROM db12405956.appointment_timetable a
JOIN instructor i on i.instructor_id = a.instructor_id
Then
SELECT top 10 *
FROM db12405956.appointment_timetable a
JOIN instructor i on i.instructor_id = a.instructor_id
JOIN appointment_start_time ad on ad.appointment_date_id = a.appointment_date_id
Finally
SELECT top 10 *
FROM db12405956.appointment_timetable a
JOIN instructor i on i.instructor_id = a.instructor_id
JOIN appointment_start_time ad on ad.appointment_date_id = a.appointment_date_id
JOIN appointment_end_time aet on aet.appointment_end_time_id = a.appointment_end_time_id
ORDER BY a.appointment_timetable_id;
At some point you will see where the records fell out and that is the location of the problem. Then you might need to look at the fields you are joining on and the data in them in your data sets to see why they are not returning any matches. For instance, if you are joining on dates, they may be stored as dates in one table and as varchar in another and date "01/01/2016' is not equal to 'Jan 1, 2016' or sometimes the column has some sort of prefix or suffix not in the other table. Something like PR2345 in one table and 2345 in the other. Sometimes the query is correct and no rows genuinely meet the conditions. This could be because the data is not fully populated yet (think writing a report for a system that is not live yet, no data on completed actions because none have completed yet.) or because the requirement was wrong in some of its assumptions or because there should be no matching records. It could even be a bug in the data entry.
Depending on the nature of the problem, you might need to return all the records or only use select top 1 (since all records are disappearing). Using SELECT * this way will help when you are returning too many or duplicate records as well as sometimes is is the fields not being returning that affect the results set. Note that I am not saying to use SELECT * in your final result set, it is only being used as a diagnostic tool here.
In your case, the problem looks as if it is in the first table. There are blanks for instructor ID and the other fields in your sample, so there is nothing to join on. (You only gave a sample so the rest of the table may not be like this.) If this is a case where the data is not there yet due to the feature that would add it not yet being live, then you can test your query only by adding test data to the table. Be sure to delete this data after you have finished unit testing. If the data should have been there, then you need to look at the insert from the application for a bug.

SQL Query to Join tables between dates

I have a MySQL database which records pager messages which has two tables, one is a table with messages and the other is a table with recipients, where the link between the tables is pagermessages.pcapcode = capcodes.bcapcode (a numerical address each pager message is sent to).
This works semi-well, and I typically use an inner or left join to show the various pager messages and who the messages are for.
The issue I have, is that the system is dynamic, and the pagers can be re-programmed so that address 1, which might have been for recipient EXAMPLE1 may eventually be changed to be for EXAMPLE 2.
This leads to the issue, that I want to store the messages in a historical form, but I need a way to be able to specify between a date range. My thought was to have in the Capcodes table a date & time (bStartDateTime) and a finish date & time (bFinishDateTime) and then in my query be able to use this to work out how to join the pager messages.
This is where I am stuck though, I would normally do something like SELECT * from PagerMessages INNER JOIN Capcodes ON PagerMessages.pCapcode = Capcodes.bCapcode however what I want to now be able to do is to do the same thing, but where the pager message date (pDateTime) is between bStartDateTime and bFinishDateTime (which could be blank) to link, but if it is outside of that then to not link.
So take this example
Pager Message Table
ID|pDateTime |pCapcode|pMessage
1 |2014-06-24 14:00|1 |This is a test message
2 |2014-06-24 15:00|1 |This is a test message
3 |2014-06-24 16:00|2 |This is a test message
Capcode Table
CapcodeID|pCapcode|Name |bStartDateTime |bFinishDateTime
1 |1 |Example 1|2014-06-24 14:00|2014-06-24 14:30
2 |1 |Example 2|2014-06-24 14:31|
3 |2 |Example 3|2014-06-24 14:31|
In the above examples, what I would like to be able to do is to join the tables so that I can get a table like the below:
ID|pDateTime |pCapcode|Name |pMessage
1 |2014-06-24 14:00|1 |Example 1|This is a test message
2 |2014-06-24 15:00|1 |Example 2|This is a test message
3 |2014-06-24 16:00|2 |Example 3|This is a test message
So you can see, basically because the capcode exists twice in the pCapcode table, it has taken the entry in which the date & time falls between, this way I can then have multiple entries of the same bCapcode in the capcode table, and then if they get changed just add the date it was changed in the Capcodes table, and add a new entry rather than having historical entries that are no longer accurate as I can't select them properly.
Sorry if it does not make too much sense, I can clarify if needed but I think i have covered most of what I am asking, which is really what kind of an SQL statement would allow me to do the above, as it is not a simple INNER / LEFT JOIN from what I can see.
Thanks!
You can still join them. Just make sure only use the finish time if it exists.
select a.id, a.pdatetime, b.name, a.pmessage
from PageMessage a
join Capcode b on a.pcapcode = b.pcapcode and b.bstartdatetime <= a.pdatetime
and (b.bfinishdatetime is null or a.pdatetime <= b.bfinishdatetime);
select ID,pdatetime,pcapcode,0 as 'Name',pmessage from Pager_Message
union
select ID,0,pcapcode,name,0 from Capcode

MySQL deleting duplicates

I updated an old site a couple of months ago moving from a Joomla install to a bespoke system. In order to convert the data from the Joomla tables to the new format I wrote various php scripts which stepped through the old records by section, processed them and inserted into the new table. All was fine until I recently discovered I had forgotten to add the die() statement to the top of one of the scripts and somehow a searchbot has been merrily pinging that script over time to add precisely 610 duplicates in one particular section.
So the things I do know about the data is that the row with the lowest ID is the row I want to keep, and the duplication only exists in CATEGORY = 8. To be sure of a duplicate, the row ORIGINAL_ID will match.
Beyond SELECT, INSERT, DELETE, I'm no MySQL expert, so confused as to how to approach this. What would the experts out their suggest?
Edit: Example code
ID CATEGORY TITLE ORIGINAL_ID
1 7 A 1
2 8 A 2
3 8 A 2
4 8 B 3
5 8 C 4
6 8 A 2
In the above example, records 3 & 6 should be stripped, because they are in CATEGORY=8, have duplicate ORIGINAL_ID; but retain the row with the lowest id (row 2)
So, you want to identify records within Category 8, where there is another record with the same Category, Title and Original_id. You also want to check if that other record has a lower ID.
So:
Select *
from MYTABLE T1
where CATGEORY = 8
and EXISTS (
select 1
from MYTABLE T2
where T2.CATEGORY=T1.CATEGORY
and T2.TITLE=T1.TITLE
where T2.ORIGINAL_ID=T1.ORIGINAL_ID
where T2.ID>T1.ID
If you run this and it returns only the records you wish to delete, replace the "select *" with a "delete" and re-run.

Print all rows from a nested Left Join + Union MySQL query

I have a query that calculates information for a revolving monthly retainer. The Project has a certain number of hours assigned to it each monthly period, with periods starting at different times of the month (e.g., February 5th to March 4th). The columns of the query result include:
Project Name
Total Hours Logged
Monthly Hours Remaining
Last Day of Period
Days Remaining
For example, Project A has 15 hours logged to it, with 5 hours remaining in the monthly period. The last day of the period is November 17th, with 3 days remaining from today.
The current Query takes 4 tables that are joined using a left join to print all of the Clients even if there are no hours logged, then it uses a nested subquery (lines 8-86) to calculate columns 2, 3, 4, and 5. However, column 4 and 5 do not print, they just show as always NULL. (Those are Last Day of Period and Days Remaining).
You can see the schema + query code at the SQL fiddle link here: http://sqlfiddle.com/#!2/fc830/12
How can I get column 4 and 5 to print the data and not be null when there are no Hours Logged? I think I may need an additional left join but I am not able to get a solution. If you have any suggestions it would be appreciated. Thanks!
When there has been no hours logged, the left join to the nested query returns nulls for the columns you're having trouble with.
The answer is to provide values for them when they are null and us ifnull() to use those value when the left join returns nulls:
select
...
ifnull(<left joined value>, <value when there's no join>),
...
See the working solution in sqlfiddle.
Incidentally, some values you are returning from the inner query, particularly the "last day" value can be derived directly from client (as seen in my solution). It's best to keep your queries as simple as possible - don't get data in a complicated way when there's an simpler or more direct way.
I think you are not thorough with the idea of LEFT JOIN. LEFT JOIN results in all rows from the outer table. Its otherwise called LEFT Outer JOIN (contrary to RIGHT OUTER JOIN). In your case the inner query results in only record with client id = 4. See the last clause X on X.id=client.id. Now what do you expect the results to be?
OUTER TABLE (client table)
id = 1, 2, 3, 4
INNER TABLE
client id = 4
ON X.id=client.id
An INNER JOIN would result in just one record since there is only matching record - for id = 4.
But a LEFT JOIN would result in all 4 records from outer table but the values for invalid fields will be NULL. Here except for client id 4, there is no valid records from inner table, hence they will be null.
To get more clarity you will have to see the id field along the records. Try this fiddle
You can see the other answer as to how to fill those NULL fields..

MYSQL: Error 1054 - Unknown Column

Before we start, I apologize for my MYSQL novice status. I'm trying to self-teach and struggling a bit with basic the basic structure.
Background on my question: Consider a company that issues bills once a quarter... and roughly two months after the end of the last quarter. I have a table (Quarter_Identify) that has several columns:
Quarter_Start EX: 01-01-2010
Quarter_End EX: 03-31-2010
Quarter_Ident EX: 1000 <--- iterating number for each quarter (next
quarter will be 1001)
Date_Billed This is the field I'm trying to populate from another table
The other table (Billing_List_1) contains:
Date_Billed EX: 05-23-2010
Lots of other nonsense related to the customers
We take all the orders during the quarter, and bill about 60 days after it ends. So, in the example above, the 5-23-2010 billing would be related to the Jan - Mar quarter (we bill really late). I would like to take this date and populate it back as the Date_Billed associated with Quart_Ident "1000".
I'm fairly close and from my research I think I'm running into the issue that my "Where" clause includes a reference to the as-yet not created table "Skyline". The "skyline" table gets everything together, but is essentially off by a month (I gave up trying to figure out the DateDiff function). So, I use the bottom piece to offset the result by one and get the right answer... except that it tells me I have an unknown column in my where clause (error 1054) the issue.
Select * from
(select Billing_List_1.date_billed, quarter_identify.quarter_start,
quarter_identify.quarter_end, quarter_identify.quarter_ident from Billing_List_1
join quarter_identify
on Billing_List_1.date_billed > quarter_identify.quarter_start
and Billing_list_1.date_billed < quarter_identify.quarter_end)
as SKYLINETABLE;
update quarter_identify A
set A.date_Billed = SKYLINETABLE.date_Billed
where A.quarter_ident = SKYLINETABLE.quarter_ident - 1
Any thoughts would be much appreciated. Have a great evening all.
Solution per TEEZ: Thanks again for the great help.
update quarter_identify A Left join
(Select * from
(select Billing_List_1.date_billed,
quarter_identify.quarter_start,
quarter_identify.quarter_end,
quarter_identify.quarter_ident from billing_list_1
join quarter_identify
on Billing_list_1.date_billed > quarter_identify.quarter_start
and Billing_list_1.date_billed < quarter_identify.quarter_end)
as T)
as SKYLINETABLE on 1
set A.date_billed = SKYLINETABLE.date_billed
where A.quarter_ident = SKYLINETABLE.quarter_ident - 1
I think you are wrong. what is SKYLINE table in update query?
You are joining tables in update query but table is not specified. you should use your first query in join with update query.
you need to use join SKYLINETABLE in join with your update query.
Like below:
update quarter_identify A left join (Select * from
(select Billing_List_1.date_billed, quarter_identify.quarter_start,
quarter_identify.quarter_end, quarter_identify.quarter_ident from Billing_List_1
join quarter_identify
on Billing_List_1.date_billed > quarter_identify.quarter_start
and Billing_list_1.date_billed < quarter_identify.quarter_end)) as SKYLINETABLE on[... specify on condition....]
set A.date_Billed = SKYLINETABLE.date_Billed
where A.quarter_ident = SKYLINETABLE.quarter_ident - 1
Please do required changes