Access SQL - Convert Text to Number - sql

I've had the same problem as described here: Access 2007 - Left Join to a query returns #Error instead of Null
for which, the solution seems to be; write a better calculated field column so that the error doesn't occur later down the line - described here: Access SQL - given two dates, return the dates of the previous period
However, my calculated column is really simple, only converting a text field to a number field (e.g. "003" -> "3");
RevisionNumber = CDbl([RevisionText])
Further to this, The process works in a left join further up the chain?!
I changed the calculated field to a constant as detailed in the comments on the answer. But this gave me a new error
"Each GROUP BY expression must contain at least one column that is not an outer reference"
Here's the comment:
In my test example, if I switched the calculated field for a constant (e.g. 3 or "Test") then this value did indeed appear for every chain, whether they appeared in the right hand side of the join or not. For a calculated field it returned an error. Only when it was a direct reference to a single field did it work properly. If I do solve it I'll post the workaround here. – Wilskt
So it must be in my SQL code??
SELECT QryDATATRIncompleteRequired.*,_
QryDATATRLatestCompleted.LevelTrained, CDbl([RevisionTrained]) AS [Revision Trained], _
QryDATATRLatestCompleted.TrainerSignOff, QryDATATRLatestCompleted.DateAwarded, _
QryDATATRLatestCompleted.ValidTo_
FROM QryDATATRIncompleteRequired LEFT JOIN QryDATATRLatestCompleted ON _
(QryDATATRIncompleteRequired.EmployeeID = QryDATATRLatestCompleted.EmployeeID) _
AND (QryDATATRIncompleteRequired.SubjectTitle = QryDATATRLatestCompleted.Subject);

Related

Referencing SQL fields from a DataSet where 2 field names are the same

I have the following SQL query which I am loading in to a DataSet:
SELECT i1.* , i2.* From tblMMLettersImportTable i1 Join tblMMLettersImportTable i2 on i1.SectionID + 1 = i2.SectionID Where i2.startpage - i1.endpage <> 1
Idea is to check that the index for various sections of a document lead one page on to the other with no gaps. I.e section 2 ends on page 5 and section 3 starts on page 6.
I'm happy that the SQL works, however by joining on itself the field "SectionID" is duplicated. In SQL easy enough, just use i1. or i2. to reference the correct one.
The issue comes when I load this in to a VB.net Dataset. I need to raise an error message with something like:
MessageBox.Show("There is a page gap between sections " & row.item("i1.sectionID") & " and " & row.item("i2.sectionID")
I get the error message Column 'i1.intline' does not belong to table Table. Makes sense as that is not its name in the dataset. I've considered using the column number to reference the item to pull out, however the SQL Table tblMMLettersImportTable is deleted, created and populated dynamically depending on the type of Letter/document being produced so I cannot always guarantee that the columns will always numbered the same. This is also why i1.* and i2.* is used instead of listing each column.
Is there a way that I can reference 2 items in a DataSet that have the same item name with VB.Net?

MS Access Append Query - Field not working

I have an append query which has an Excel Sheet as a datasource. Today the underlying data of one of the fields was changed from String to Long. In my query table I had this particular field calculated as:
MSCI: Left([bp_msci_ic_key];2)
in order to compensate for the change in underlying data format I changed it to...
MSCI: Left(*Str*([bp_msci_ic_key]);2)
Unfortunately, the query produces #ERROR with this... why does this approach not work?
Here the syntax of the entire SQL statement:
INSERT INTO tbl_Position(
MoPo_ID,
AssetClass_Sub_ID,
VALOR,
ISIN,
[Currency],
Position_Name,
Weight,
Rating,
Asset_Country,
Issuer_Country,
Position_Duration,
Position_YieldToMaturity,
MSCI_Code,
PosValue)
SELECT
qry_Position_Load_step1.MoPo_BM_ID,
qry_Position_Load_step1.AssetClass_Sub_ID,
qry_Position_Load_step1.VALOR,
qry_Position_Load_step1.ISIN,
IIf([qry_Position_load_step1]![ccy] Is Null And Left([qry_Position_load_step1]![classsub],2)="M_", Mid([qry_Position_load_step1]![classsub],3,Len([qry_Position_load_step1]![classsub])-1),[qry_Position_load_step1]![CCY]) AS CCY,
qry_Position_Load_step1.NAME_SHORT,
qry_Position_Load_step1.Val,
tbl_MopoRohdaten.rating_clir,
tbl_MopoRohdaten.ass_domi_country,
tbl_MopoRohdaten.iss_domi_country,
tbl_MopoRohdaten.pos_dur_mod,
tbl_MopoRohdaten.pos_ytm,
Left(Str([bp_msci_ic_key]),2) AS MSCI,
tbl_MopoRohdaten.pos_eop_value
FROM
qry_Position_Load_step1
LEFT JOIN tbl_MopoRohdaten ON
(qry_Position_Load_step1.MoPo_Name_Avaloq = tbl_MopoRohdaten.portf_name) AND
(qry_Position_Load_step1.ISIN = tbl_MopoRohdaten.asset_isin);
EDIT: A reduced Selection as per comments:
SELECT
tbl_MopoRohdaten.[bp_msci_ic_key] AS MSCI
FROM
qry_Position_Load_step1
LEFT JOIN tbl_MopoRohdaten ON
(qry_Position_Load_step1.MoPo_Name_Avaloq = tbl_MopoRohdaten.portf_name) AND
(qry_Position_Load_step1.ISIN = tbl_MopoRohdaten.asset_isin)
WHERE
(((tbl_MopoRohdaten.[bp_msci_ic_key]) Is Not Null));
The problem occurred because the underlying data had a broked/incomplete record source. For reasons I am not certain of yet, only a fraction of the underlying data in tbl_MopoRohdaten got loaded. Since the query used a double join in matching up the data, it kept on showing a number of records that matched one of the joins.
However, the results that were returned never contained any data for the MSCI field I was having problems with. So naturally, when I used CStr() it returned an error, because the field was Null.

MS Access Update SQL Query Extremely Slow and Multiplying the Amount of Records Updated

I am stumped on how to make this query run more efficiently/correctly. Here is the query first and then I can describe the tables that are involved:
UPDATE agg_pivot_test AS p
LEFT JOIN jd_cleaning AS c
ON c.Formerly = IIF(c.Formerly LIKE '*or*', '*' & p.LyFinalCode & '*', CStr(p.LyFinalCode))
SET p.CyFinalCode = c.FinalCode
WHERE p.CyFinalCode IS NULL AND c.Formerly IS NOT NULL;
agg_pivot_test has 200 rows of data and only 99 fit the criteria of WHERE p.CyFinalCode IS NULL. The JOIN needs some explaining. It is an IIF because some genius decided to link last year's data to this year's data using Formerly. It is a string because sometimes multiple items have been consolidated down to one so they use "or" (e.g., 632 or 631 or 630). So if I want to match this year's data I have to use Formerly to match last year's LyFinalCode. So this year the code might be 629, but I have to use the Formerly to map the items that were 632, 631, or 630 to the new code. Make sense? That is why the ON has an IIF. Also, Formerly is a string and LyFinalCode is an integer... fun.
Anyway, when you run the query it says it is updating 1807 records when again, there are only 200 records and only 99 that fit the criteria.
Any suggestions about what this is happening or how to fix it?
An interesting problem. I don't think I've ever come across something quite like this before.
I'm guessing what's happening is that rows where CyFinalCode is null, are being matched multiple times by the join statement, and thus the join expression is calculating a cartesian product of row-matches, and this is the basis of the rows updated message. It seems odd, as I would have expected access to complain about multiple row matches, when row matches should only be 1:1 in an update statement.
I would suggest rewriting the query (with this join) as a select statement, and seeing what the query gives you in the way of output; Something like:
SELECT p.*, c.*
FROM agg_pivot_test p LEFT JOIN jd_cleaning c
ON c.Formerly = IIF(c.Formerly LIKE '*or*', '*' & p.LyFinalCode & '*', CStr(p.LyFinalCode))
WHERE p.CyFinalCode IS NULL AND c.Formerly IS NOT NULL
I'm also inclined to suggest changing "... & p.LyFinalCode & ..." to "... & CStr(p.LyFinalCode) & ..." - though I can't really see why it should make a difference.
The only other thing I can think to suggest is change the join a bit: (this isnt guaranteed to be better necessarily - though it might be)
UPDATE agg_pivot_test AS p LEFT JOIN jd_cleaning AS c
ON (c.Formerly = CStr(p.LyFinalCode) OR InStr(c.Formerly, CStr(p.LyFinalCode)) > 0)
(Given the syntax of your statement, I assume this sql is running within access via ODBC; in which case this should be fine. If I'm wrong the sql is running server side, you'll need to change InStr to SubString.)

SQL MIN() returns multiple values?

I am using SQL server 2005, querying with Web Developer 2010, and the min function appears to be returning more than one value (for each ID returned, see below). Ideally I would like it to just return the one for each ID.
SELECT Production.WorksOrderOperations.WorksOrderNumber,
MIN(Production.WorksOrderOperations.OperationNumber) AS Expr1,
Production.Resources.ResourceCode,
Production.Resources.ResourceDescription,
Production.WorksOrderExcel_ExcelExport_View.PartNumber,
Production.WorksOrderOperations.PlannedQuantity,
Production.WorksOrderOperations.PlannedSetTime,
Production.WorksOrderOperations.PlannedRunTime
FROM Production.WorksOrderOperations
INNER JOIN Production.Resources
ON Production.WorksOrderOperations.ResourceID = Production.Resources.ResourceID
INNER JOIN Production.WorksOrderExcel_ExcelExport_View
ON Production.WorksOrderOperations.WorksOrderNumber = Production.WorksOrderExcel_ExcelExport_View.WorksOrderNumber
WHERE Production.WorksOrderOperations.WorksOrderNumber IN
( SELECT WorksOrderNumber
FROM Production.WorksOrderExcel_ExcelExport_View AS WorksOrderExcel_ExcelExport_View_1
WHERE (WorksOrderSuffixStatus = 'Proposed'))
AND Production.Resources.ResourceCode IN ('1303', '1604')
GROUP BY Production.WorksOrderOperations.WorksOrderNumber,
Production.Resources.ResourceCode,
Production.Resources.ResourceDescription,
Production.WorksOrderExcel_ExcelExport_View.PartNumber,
Production.WorksOrderOperations.PlannedQuantity,
Production.WorksOrderOperations.PlannedSetTime,
Production.WorksOrderOperations.PlannedRunTime
If you can get your head around it, I am selecting certain columns from multiple tables where the WorksOrderNumber is also contained within a subquery, and numerous other conditions.
Result set looks a little like this, have blurred out irrelevant data.
http://i.stack.imgur.com/5UFIp.png (Wouldn't let me embed image).
The highlighted rows are NOT supposed to be there, I cannot explicitly filter them out, as this result set will be updated daily and it is likely to happen with a different record.
I have tried casting and converting the OperationNumber to numerous other data types, varchar type returns '100' instead of the '30'. Also tried searching search engines, no one seems to have the same problem.
I did not structure the tables (they're horribly normalised), and it is not possible to restructure them.
Any ideas appreciated, many thanks.
The MIN function returns the minimum within the group.
If you want the minimum for each ID you need to get group on just ID.
I assume that by "ID" you are referring to Production.WorksOrderOperations.WorksOrderNumber.
You can add this as a "table" in your SQL:
(SELECT Production.WorksOrderOperations.WorksOrderNumber,
MIN(Production.WorksOrderOperations.OperationNumber)
FROM Production.WorksOrderOperations
GROUP BY Production.WorksOrderOperations.WorksOrderNumber)

SQL statement HAVING MAX(some+thing)=some+thing

I'm having trouble with Microsoft Access 2003, it's complaining about this statement:
select cardnr
from change
where year(date)<2009
group by cardnr
having max(time+date) = (time+date) and cardto='VIP'
What I want to do is, for every distinct cardnr in the table change, to find the row with the latest (time+date) that is before year 2009, and then just select the rows with cardto='VIP'.
This validator says it's OK, Access says it's not OK.
This is the message I get: "you tried to execute a query that does not include the specified expression 'max(time+date)=time+date and cardto='VIP' and cardnr=' as part of an aggregate function."
Could someone please explain what I'm doing wrong and the right way to do it? Thanks
Note: The field and table names are translated and do not collide with any reserved words, I have no trouble with the names.
Try to think of it like this - HAVING is applied after the aggregation is done.
Therefore it can not compare to unaggregated expressions (neither for time+date, nor for cardto).
However, to get the last (principle is the same for getting rows related to other aggregated functions as weel) time and date you can do something like:
SELECT cardnr
FROM change main
WHERE time+date IN (SELECT MAX(time+date)
FROM change sub
WHERE sub.cardnr = main.cardnr AND
year(date)<2009
AND cardto='VIP')
(assuming that date part on your time field is the same for all the records; having two fields for date/time is not in your best interest and also using reserved words for field names can backfire in certain cases)
It works because the subquery is filtered only on the records that you are interested in from the outer query.
Applying the same year(date)<200 and cardto='VIP' to the outer query can improve performance further.