I am appending data from an Access query into an existing table in SQL Server (2019) and sometimes NULL values cause a "Record is deleted" msgbox (no error number).
For instance, I have 3 columns (Text1, Text2, Text3) all are nvarchar(255) and Text1 accepts NULL values but sometimes Text2 doesn't... they are literally the same field with the same data. There is absolutely nothing different with the columns in SQL Server nor the fields in the query. This shouldn't be happening.
The other thing is that I made a make-table query off of the query and using that new table instead of the query caused no problems at all! Why is this? and how do I get the query to append data consistently?
I have tried append queries as well as straight up SQL in a DoCmd.RunSQL
The SqlSRV table is connected via custom ODBC string in Linked Table Manager.
From a query; this gives errors:
INSERT INTO tmakContact ( DataAsOf, ContactId, FullName, LoanNum, LoanId, Name, JobTitle, Email, Relationship, Company, Address, CityStateZip, [Number], PhoneNumType )
SELECT DataAsOf, ContactId, FullName, LoanNum, LoanId, Name, JobTitle, Email, Relationship, Company, Address, CityStateZip, [Number], PhoneNumType
FROM qryContact;
When I take out "Relationship" and "PhoneNumType" fields, the INSERT from this query works fine. These two fields come from outer joined tables. These tables are from another SQL Server and database I link to from within Access via custom ODBC string in Linked Table Manager.
From a table which I made in a make table query from qryContact gives no errors!
INSERT INTO tmakContact ( DataAsOf, ContactId, FullName, LoanNum, LoanId, Name, JobTitle, Email, Relationship, Company, Address, CityStateZip, [Number], PhoneNumType )
SELECT DataAsOf, ContactId, FullName, LoanNum, LoanId, Name, JobTitle, Email, Relationship, Company, Address, CityStateZip, [Number], PhoneNumType
FROM tmptblContact;
Originally I just ran DoCmd.OpenQuery "apdContact" which doesn’t work, which is just a saved append query using the same code as above.
SQL for qryContact:
SELECT Now() AS DataAsOf, dbo_Contact.Id AS ContactId, dbo_UserInfo.FullName, dbo_Loaninfo.LoanNum, dbo_ContactLoanLink.LoanId, dbo_Contact.Name, dbo_Contact.JobTitle, dbo_Email.Addr AS Email, Trim([dbo_ContactRelationship]![Descr]) AS Relationship, dbo_Contact.Company, [Add1] & " " & [Add2] AS Address, StrConv([City],3) & ", " & [StateCode] & " " & [Zip] AS CityStateZip, qryPhone.Number, qryPhone.PhoneNumType
FROM ((((dbo_Loaninfo INNER JOIN ((dbo_ContactLoanLink INNER JOIN dbo_Contact ON dbo_ContactLoanLink.ContactId = dbo_Contact.Id) LEFT JOIN dbo_Address ON dbo_Contact.BusAddrAId = dbo_Address.Id) ON dbo_Loaninfo.Id = dbo_ContactLoanLink.LoanId) LEFT JOIN dbo_ContactRelationship ON dbo_ContactLoanLink.ContactRelationshipId = dbo_ContactRelationship.Id) LEFT JOIN dbo_Email ON dbo_Contact.Id = dbo_Email.ContactId) LEFT JOIN qryPhone ON dbo_Contact.Id = qryPhone.ContactId) LEFT JOIN dbo_UserInfo ON dbo_Loaninfo.AssignedUserId = dbo_UserInfo.Id
WHERE (((dbo_Contact.InactiveFlag)="N") AND ((dbo_Loaninfo.LoanStatusId)<>1105) AND ((dbo_Loaninfo.InactiveFlag)="N") AND ((dbo_Loaninfo.PaidOffFlag)="N"));
Hum, does the table in question have any true/false columns - even if not used in your query? (a bit column in the table?).
Double, triple check that the target table in SQL server (no doublt a linked table to Access) has any bit columns, and if yes, MAKE SURE the column has a deafult value (0), for false.
Next up:
You don't mention if the target table in question has a autonumber PK column (I suspect it must have - but do check, and make sure that such a table has a PK).
next up:
Are their any real, or single/double columns in that target table - Again EVEN IF THEY ARE NOT part of your query, make sure such columns have a default setting in sql server (0).
last up:
Add a row version column to the sql server target table. That so called "row version" column in sql is named timestamp. (this is the worlds WORST name, since that timestamp column has ZERO to do with "time" or date or whatever. it is a ACTUAL row version system, and access supports this feature.
It also means that access will not do a column by column compare to the record when doing updates, or inserts. So, try adding a timestamp (aka: row version) column to the target table, and re-link from access.
Related
I have a legacy database in SQL set up like a spreadsheet with 50 columns. Apart from employee names, the field names would be Machine01, Machine02, etc. and the records would include the date certified on each machine. I am using Access as a legacy front end because there is already so much already coded and staff trained with it.
How would I go about writing a query that would provide the dates each person is certified on, say, Machine27?
In Access, I initially had
SELECT LastName, FirstName, Forms![F: Reports Switchboard]![Machine Name] As Expr1
FROM Certifications
WHERE Forms![F: Reports Switchboard]![Machine Name]>""
But this provides a column filled with the machine name, not the dates in the field with that name.
I tried a number of other methods including a stored procedure:
CREATE PROCEDURE sp_CertDate
#fieldvar1 varchar(20)
AS
SELECT LastName, FirstName, #fieldvar1
FROM Certifications
WHERE Forms![F: Reports Switchboard]![Machine Name]>""
GO
But again, I just get the field name in the query, not the record data for the field.
I think I am missing something obvious, but I need a push in the right direction. Any help would be appreciated.
Since the machine name is a column of table, it is a structural component of the SQL statement and not string literal. Hence, you need to create a dynamic query object which you can handle in VBA using QueryDefs:
Dim qDef As QueryDef
Dim strSQL As String
strSQL = "SELECT LastName, FirstName, " _
& "[" & Forms![F: Reports Switchboard]![Machine Name] & "] As MachineDate " _
& "FROM Certifications " _
& "WHERE [" & Forms![F: Reports Switchboard]![Machine Name] & "] >'' "
Set qdef = CurrentDb.QueryDefs("mySavedQuery") ' LOCATE SAVED QUERY
qdef.SQL = strSQL ' CHANGE ITS SQL
Set qdef = Nothing ' RELEASE OBJECT TO SAVE
But ideally if you can avoid wide formatted data since you never want to save data elements in column headers. As one DBA guru says, Why would you need to create a table with even 20 columns, let alone 2000 ???.
Instead use a more normalized, long table format and avoid complex queries:
LastName
FirstName
Machine
Date
Stacks
Rick
Machine01
5/1/21
Stacks
Rick
Machine02
5/15/21
Stacks
Rick
Machine03
5/20/21
...
...
...
...
Doing so, requires no VBA but a single, static SQL query:
SELECT LastName, FirstName, Machine, [Date]
FROM Certifications
WHERE Machine = Forms![F: Reports Switchboard]![Machine Name]
Table and Field names cannot be dynamic in Access query object.
I will assume there is a unique identifier field something like EmpID. If there isn't, there should be.
Possible options:
every machine field would have same criteria with OR operator - 50 fields might hit limit on number of OR operators, apparently there is a limit of 99 AND operators
build a UNION query to rearrange machine fields to normalized structure and use that query as source for another query to do search - UNION has a limit of 50 SELECT lines so might just barely work and there is no builder or wizard for UNION, must type or copy/paste in SQLView
SELECT EmpID, LastName, FirstName, Machine01 AS CertDate, "Machine01" AS MachineName FROM Certifications
UNION SELECT EmpID, LastName, FirstName, Machine02, "Machine02" FROM Certifications
...;
use DLookup domain aggregate function on designated machine field, reference form control for field argument input
SELECT EmpID, LastName, FirstName, Forms![F: Reports Switchboard]![Machine Name] AS MachineName,
DLookup("[" & Forms![F: Reports Switchboard]![Machine Name] & "]", "Certifications", "EmpID=" & [EmpID]) AS CertDate
FROM Certifications;
VBA and QueryDefs to modify query object
I'm trying to update a report (report builder) on SQL Server, which is based upon a stored procedure.
The stored procedure as is - queries 2 tables via INNER JOIN but was only designed to display data from 1 table.
I'm trying to get it now to also display some data from the 2nd table.
While it executes fine, its not displaying any data from the 2nd table.
Code:
SELECT n.ID, COMPANY, TITLE, EMAIL, FULL_NAME, chapter, n.member_type, ng.INDUSTRY_CLASS
from name n
inner join name_general ng on n.id = ng.id
WHERE MEMBER_TYPE in ('A','B','C','D', 'E','F','G')
and n.STATUS = 'A'
and N.EMAIL <> ''
and ng.no_mail = 0
and (
( charindex ( chapter,'WA') > 0 ))
This was originally written by past people & it works as wanted, and the only thing I've added is the ng.INDUSTRY_CLASS within the select statement. But when this is executed, no data displays for INDUSTRY_CLASS
*Obviously this is a partial extract of the stored procedure.
*Running on Server 2016 / SQL Server 2016
Sorry, ignore this question.
I realized that INDUSTRY_CLASS is on the Company Record & not an Individual's record.
Its a badly designed DB, in this same name table we have rows of people & rows of companies.
Obviously therefore both people & companies have the same fields.
The INDUSTRY_CLASS field is null for people, as that data is with a Company.
So both People and Companies have n.id in the name table & they also have n.co_id.
On a record for a person the n.co_id is just the n.id of the company from the same table.
This was the design of the CRM Manaufacturer... all im doing is querying the CRM db.
I am aware this has been asked multiple times, but for one reason or another the solutions are not working for me.
Database Layout:
I have Table1 (Scanner_Location) Who is getting data pulled from another table/ subform on a form (Scanner IBOB) * Holds Columns: FP#, Count, Location, Model_ID, PK-SL_ID
Table2 (Scanner Detail) Holds Two of the three data columns: (FP#, Location PK-SN)
Table3 (Scanner_Model) Holds the last data column, displayed in a subform. (PK-Model_ID)
The user will input FP#, and location in one section of the form, then navigate to the subform, and select multiple Models, and enter the count (Textbox). Once Selected, they click an 'update' button that executes my queries. (Of which I have an update, AND an Append Query)
The problem is, just using an update query doesn't add the records. And using an Append query creates duplicates of the existing data.
Here's how the flow carries out:
User selects Model 1 and Model 2 with a count of 4 and an FP# of 100. Clicks update.
The queries update, and the information enters correctly.
User Selects the same models again (Model_Select), with the same FP# and count, the Table1 has the same information entered again, with a different primary key.
The goal:
The append query creates duplicates of existing data. I only want my update and/or append queries to:
Update the existing data - Looking for anything with the same FP#
Add any records that do not exist already (Looking at Model_ID and FP#)
INSERT INTO Scanner_Location ( Model_ID, FootPrints_Num, Location_ID, Scanner_Loc_Cnt )
SELECT Scanner_Model.Model_ID, [Forms]![Scanner_IBOB]![fpNum_txt] AS [FP#],
[Forms]![Scanner_IBOB]![Location_Cbo_main] AS Location,
[Forms]![Scanner_IBOB]![Scanner_Loc_CntTxt] AS [Count]
FROM Scanner_Detail
RIGHT JOIN Scanner_Model ON Scanner_Detail.Model_ID = Scanner_Model.Model_ID
WHERE (((Scanner_Model.SM_Acc_Select)=True)
AND ((NOT Exists (SELECT * FROM Scanner_location
WHERE (((Forms!Scanner_IBOB!fpNum_txt)=Forms!Scanner_IBOB!fpNum_txt)
And ((Scanner_Model.SM_Acc_Select)=True)); ))=False));
No query named 'Update_SLoc_Acc53' - there are 'Update_SLoc_Acc3' and 'Update_SLoc_Acc54'. I modified 'Update_SLoc_Acc54' because it is the one called by the code.
The query was not pulling the Location_ID from the combobox. I found the Bound Column was set to 1 and should be 0 to reference the Location_ID column because column index begins with 0. Can hide this column from user by setting width to 0.
This query seems to work:
INSERT INTO Scanner_Location ( Model_ID, FootPrints_Num, Location_ID, Scanner_Loc_Cnt )
SELECT Scanner_Model.Model_ID, [Forms]![Scanner_IBOB]![fpNum_txt] AS FPNum,
[Forms]![Scanner_IBOB]![Location_Cbo_main] AS Location,
[Forms]![Scanner_IBOB]![Scanner_Loc_CntTxt] AS CountMod
FROM Scanner_Model
WHERE (((Scanner_Model.SM_Acc_Select)<>False)
AND (([Model_ID] & [Forms]![Scanner_IBOB]![fpNum_txt] &
[Forms]![Scanner_IBOB]![Location_Cbo_main])
NOT IN (SELECT Model_ID & Footprints_Num & Location_ID FROM Scanner_Location)));
Note I did not use # in field name. Advise not to use punctuation/special characters in names with only exception of underscore. Also used CountMod instead of Count as field name.
Why the requirement to select two models? What if one is added and the other isn't?
I have concerns about the db structure.
Don't think App_Location and App_Detail should both be linking to other tables. Why is Location_ID the primary key in App_Location as well as primary key in Location_Data? This is a 1-to-1 relationship.
Is Serial_Number the serial number for scanner? Why is it a primary key in Telnet? This also results in a 1-to-1 relationship in which case might as well combine them.
If an app is associated with a scanner and scanner is associated with a location then don't need location associated with app. Same goes for scanner and telnet.
Scanner_Location table is not linked to anything. If purpose of this table is to track a count of models/footprints/locations -- as already advised this is usually not a good idea. Ideally, count data should be calculated by aggregate query of raw data records when the information is needed.
Maybe use NOT IN, something like:
[some identifier field] NOT IN (SELECT [some identifier field] FROM
Review EXISTS vs IN
Consider following adjusted append query that checks existence of matched Model_ID and FP_Num in Scanner_Location. If matches do not exist, then query imports selected records as they would be new records and not duplicates. Also, table aliases are used for readability and subquery correlation.
INSERT INTO Scanner_Location ( Model_ID, FootPrints_Num, Location_ID, Scanner_Loc_Cnt )
SELECT m.Model_ID, [Forms]![Scanner_IBOB]![fpNum_txt] AS [FP#],
[Forms]![Scanner_IBOB]![Location_Cbo_main] AS Location,
[Forms]![Scanner_IBOB]![Scanner_Loc_CntTxt] AS [Count]
FROM Scanner_Detail d
RIGHT JOIN Scanner_Model m ON d.Model_ID = m.Model_ID
WHERE ((m.SM_Acc_Select = True)
AND (NOT EXISTS (SELECT 1 FROM Scanner_Location loc
WHERE ((loc.FootPrints_Num = Forms!Scanner_IBOB!fpNum_txt)
AND (loc.Model_ID = m.Model_ID)) ) ));
I have to write a t-sql merge statement where I have to meet multiple conditions to match.
Table column names:
ID,
emailaddress,
firstname,
surname,
titile,
mobile,
dob,
accountnumber,
address,
postcode
The main problem here is that, the database I am working with does not have mandatory fields, there is no primary keys to compare, and source table can have duplicates records as well. As a result, there are many combination to check for the duplicates of source table against the target table. My manager have come up with following scenario
We could have data where two people using same email address so emailaddress, firstname and surname match is 100% match (thinking all other columns else are empty)
data where mobile and accountnumber match is 100% match (thinking all other columns else are empty)
title, surname, postcode, dob match is 100% match (thinking all other columns else are empty)
I was given this task where I cannot see the data because I am a new recruit and my employee does not want to me to see this data for the moment. So, I am kind of working with my imagination.
The solution Now, I am thinking rather than checking the existing record of source against target database, I will cleanse the source data using stored procedure statements, where if it meets one duplicate condition then it will skip the next duplicate removing statements and insert the data into target table.
with cte_duplicate1 AS
(
select emailaddress, sname, ROW_NUMBER() over(partition by emailaddress, sname order by emailaddress) as dup1
from DuplicateRecordTable1
)
delete from cte_duplicate1
where dup1>1;
(if the first cte_duplicate1 code was executed then it will skip the cte_duplicate2)
with cte_duplicate2 AS
(
select emailaddress, fname, ROW_NUMBER() over(partition by emailaddress, fname order by emailaddress) as dup2
from DuplicateRecordTable1
)
delete from cte_duplicate2
where dup2>1;
That is the vague plan at the moment. I do not know yet, if it achievable or not.
I have given a job where I cannot see the data because I am new recruit and my employee does not want to me to give me data to work with. So, I am kind of working with my imagination.
Anyway, the main problem here is that, the database I am working with does not have mandatory fields, there is no primary keys to compare, and source table can have duplicates records as well. As a result, there are many combination to check for the duplicates of source table against the target table.
The solution
Now, I am thinking rather than checking the existing record of source against target database, I will cleanse the source data using stored procedure statements, where if it meets one duplicate condition then it will skip the next duplicate removing statements and insert the data into target table.
with cte_duplicate1 AS
(
select emailaddress, sname, ROW_NUMBER() over(partition by emailaddress, sname order by emailaddress) as dup1
from DuplicateRecordTable1
)
delete from cte_duplicate1
where dup1>1;
(if the first cte_duplicate1 code was executed then it will skip the cte_duplicate2)
with cte_duplicate2 AS
(
select emailaddress, fname, ROW_NUMBER() over(partition by emailaddress, fname order by emailaddress) as dup2
from DuplicateRecordTable1
)
delete from cte_duplicate2
where dup2>1;
That is the vague plan at the moment. I do not know yet, if it achievable or not.
I found how to use SUM and GROUP BY within one table. What I try to do is to sum one field (Marks.m_GPA) in one table depending on a field in a second table (Curriculum.[c_Subject Group]).
I have one table with all the results of the students named Marks and another table named Curriculum. Both tables have the subject code in common (c_Code and m_Code), the Curriculum table has got one field [c_Subject Group]. I want to have the sum of all m_GPA values for each [c_Subject Group] and the results GROUP BY [c_Subject Group].
All fields are strings (text).
It's an ADO SQL VB6 application where I use the MS Jet engine of Access. I usually try to run a query using Access to test the query beforehand, ACCESS seems to accept my syntax, but the result is an empty table.
Here is the query:
SELECT
Curriculum.[c_Subject Group],
Sum([m_GPA]) AS Total_GPA
FROM Curriculum
INNER JOIN Marks ON
Curriculum.c_Code = Marks.m_Code
WHERE Curriculum.[c_Subject Group]= "1"
GROUP BY Curriculum.[c_Subject Group];
Even if I try Sum(cdbl(Marks.[m_GPA])), the result is an empty table.
Try this one.
SELECT
Curriculum.[c_Subject Group],
Marks.Total_GPA
FROM Curriculum
LEFT JOIN (
SELECT
m_Code,
Sum([m_GPA]) AS Total_GPA
FROM Marks
GROUP BY m_Code
)Marks
ON Curriculum.c_Code = Marks.m_Code
WHERE Curriculum.[c_Subject Group]= '1'