Using MS Access, via VBA, I have been trying to update an main Access database table from an identically structured external Access database table. Same columns, same fields. The external databases are used to update a central main database.
What I have been trying to develop is a line of SQL that only appends the entries that are completely unique. Because there is no foreign keys or unique identifiers for the incoming data that can be referenced, I am required to check each field to make sure that there are no exact duplicates. So, if the table had 2 fields, if entries failed the logic test
intTable.field1 = extTable.field1 And intTable.field2 = extTable.field2
then those are the entries that would be appended.
The code I came up with is below, and when it runs it tries to append (in a Gary Oldman voice) EVERYTHING. I can't find out what could be wrong with it, as it's almost like it ignores the WHERE or WHERE NOT EXIST. I have tried dozens of small edits and alternate versions. Either is appends all or none.
INSERT INTO Table1
SELECT field1, field2, field3, field4, field5
FROM [;DATABASE=C:\extDB.accdb].[Table1] sourceDB
WHERE NOT EXISTS (SELECT *
FROM [;DATABASE=C:\extDB.accdb].[Table1] sourceDB1
WHERE ('Table1.[field1]'='sourceDB1.[field1]' And
'Table1.[field2]'='sourceDB1.[field2]' And
'Table1.[field3]'='sourceDB1.[field3]' And
'Table1.[field4]'='sourceDB1.[field4]' And
'Table1.[field5]'='sourceDB1.[field5]'));
FINAL CODE (after implementing ArcherBird's solution):
INSERT INTO Table1
SELECT field1, field2, field3, field4, field5
FROM [;DATABASE=C:\extDB.accdb].[Table1] sourceDB
WHERE NOT EXISTS (SELECT *
FROM [;DATABASE=C:\extDB.accdb].[Table1] sourceDB1
WHERE ((sourceDB.[field1] = sourceDB1.[field1] Or (sourceDB.[field1] IS NULL And sourceDB1.[field1] IS NULL)) And
(sourceDB.[field2] = sourceDB1.[field2] Or (sourceDB.[field2] IS NULL And sourceDB1.[field2] IS NULL)) And
(sourceDB.[field3] = sourceDB1.[field3] Or (sourceDB.[field3] IS NULL And sourceDB1.[field3] IS NULL)) And
(sourceDB.[field4] = sourceDB1.[field4] Or (sourceDB.[field4] IS NULL And sourceDB1.[field4] IS NULL)) And
(sourceDB.[field5] = sourceDB1.[field5] Or (sourceDB.[field5] IS NULL And sourceDB1.[field5] IS NULL)) ));
1) Remove the string quotes from your field comparison logic.
2) You have aliased Table1 in your query as sourceDB, so use that reference.
3) The table where you check for non-existence ought to be the "local" version of Table1 (the one you are inserting into).
INSERT INTO Table1
SELECT field1,
field2,
field3,
field4,
field5
FROM [;DATABASE=C:\extDB.accdb].[Table1] sourceDB
WHERE NOT EXISTS (SELECT *
FROM [Table1] sourceDB1
WHERE (sourceDB.[field1] = sourceDB1.[field1] And
sourceDB.[field2] = sourceDB1.[field2] And
sourceDB.[field3] = sourceDB1.[field3] And
sourceDB.[field4] = sourceDB1.[field4] And
sourceDB.[field5] = sourceDB1.[field5]));
EDIT:
To deal with the case where these fields might have null values, you cannot do a simple = comparison since null does not equal null. The best way I can think of to get around this in MS Access would be to replace null with some other value that is not likely to be used. In doing so, you also need to make sure you chose replacement values that are consistent with the data type. I will make an assumption that all your fields are text.
INSERT INTO Table1
SELECT field1,
field2,
field3,
field4,
field5
FROM [;DATABASE=C:\extDB.accdb].[Table1] sourceDB
WHERE NOT EXISTS (SELECT *
FROM [Table1] sourceDB1
WHERE (nz(sourceDB.[field1],"!##") = nz(sourceDB1.[field1],"!##") And
nz(sourceDB.[field2],"!##") = nz(sourceDB1.[field2],"!##") And
nz(sourceDB.[field3],"!##") = nz(sourceDB1.[field3],"!##") And
nz(sourceDB.[field4],"!##") = nz(sourceDB1.[field4],"!##") And
nz(sourceDB.[field5],"!##") = nz(sourceDB1.[field5],"!##")));
Related
I'm trying to create a temporary table with a select into statement in a stored procedure as follows:
SELECT *
INTO #GENEALOGY
FROM
(
SELECT field1, field2,
(SELECT fieldA from tableY WHERE...) as field3,
(SELECT fieldB from tableY WHERE...) as field4
FROM table
WHERE condition
)
Any command I type after this closing bracket fails the syntax check (such as another SELECT statement).
I've tried putting BEGIN and END before and after the whole statement and then starting my next command.
I've tried adding
AS tablename
after the closing bracket and then the next statement but it doesn't like that either
I've tried removing the # but same problem.
I actually need to run a WHILE loop after this and INSERT more records into the same table.
What am i doing wrong?
thanks
Out of curiosity, why are you using a subquery?
SELECT field1, field2,
(SELECT fieldA from tableY WHERE...) as field3,
(SELECT fieldB from tableY WHERE...) as field4
INTO #GENEAOLOGY
FROM table
WHERE condition;
The structure of your query is ok. You should include a semi-colon at the end, if this is in a programming block. I assume table is a real name and that the other parts of the query are syntactically correct.
What does the error mention? If you run this in SSMS more than once, the second time the temp table already exists and could be an error.
You said an alias was not enough, but this is a right sentence:
SELECT *
INTO #GENEALOGY
FROM
(
SELECT field1, field2,
(SELECT fieldA from tableY WHERE...) as field3,
(SELECT fieldB from tableY WHERE...) as field4
FROM table
WHERE condition
) as TableNameAlias
thanks guys for the help
in the end I changed to an INSERT INTO rather than a SELECT INTO because
a) i needed to do 2 different select queries to get the data i need (1 for the first record and a 2nd for all subsequent records) and the second query would have had to be an INSERT anyway
b) and i wasn't sure how long sql server would keep the temp table open if i was calling the procedure from a crystal report
so i created a fixed table, use SELECT INTO and just delete all records as first line of my sp to clear out unwanted data
ta!
I have a a large customer database where customers have been added multiple times in some circumstances which is causing problems. I am able to use a query to identify the records which are an exact match, although some records have slight variations such as different addresses or given names.
I want to query across 10 fields, some records will match all 10 which is clearly a duplicate although other fields may only match 5 fields with another record and require further investigation. Therefore i want to create a results set which has field with a count how many fields have been matched. Basically to create a rating of the likely hood the result is an actual match. All 10 would be a clear dup but 5 would only be a possible duplicate.
Some will only match on POSTCODE and FIRSTNAME which is generally can be discounted.
Something like this helps but as it only returns records which explicitly match on all 3 records its not really useful due the sheer amount of data.
SELECT field1,field2,field3, count(*)
FROM table_name
GROUP BY field1,field2,field3
HAVING count(*) > 1
You are just missing the magic of CUBE(), which generates all the combinations of columns automatically
DECLARE #duplicate_column_threshold int = 5;
WITH cte AS (
SELECT
field1,field2,...,field10
,duplicate_column_count = (SELECT COUNT(col) FROM (VALUES (field1),(field2),...,(field10)) c(col))
FROM table_name
GROUP BY CUBE(field1,field2,...,field10)
HAVING COUNT(*) > 1
)
SELECT *
INTO #duplicated_rows
FROM cte
WHERE duplicate_column_count >= #duplicate_column_threshold
Update: to fetch the rows from the original table, join it against the #duplicated_rows using a technique that treats NULLs as wildcards when comparing the columns.
SELECT
a.*
,b.duplicate_column_count
FROM table_name a
INNER JOIN #duplicated_rows b
ON NULLIF(b.field1,a.field1) IS NULL
AND NULLIF(b.field2,a.field2) IS NULL
...
AND NULLIF(b.field10,a.field10) IS NULL
You might try something like
Select field1, field2, field3, ... , field10, count(1)
from customerdatabase
group by field1, field2, field3, ... , field10
order by field1, field2, field3, ... , field10
Where field1 through field10 are ordered by the "most identifiable/important" to least.
This is as close I've got to what i'm trying to achieve, which will return all records which have any duplicate fields. I want to add a column to the results which indicate how many fields have matched any other record in the table. There are around 40,000 records in total.
select * from [CUST].[dbo].[REPORTA] as a
where exists
(select [GIVEN.NAMES],[FAMILY.NAME],[DATE.OF.BIRTH],[POST.CODE],[STREET],[TOWN.COUNTRY]
from [CUST].[dbo].[REPORTA] as b
where a.[GIVEN.NAMES] = b.[GIVEN.NAMES]
or a.[FAMILY.NAME] = b.[FAMILY.NAME]
or a.[DATE.OF.BIRTH] = b.[DATE.OF.BIRTH]
or a.[POST.CODE] = b.[POST.CODE]
or a.[STREET] = b.[STREET]
or a.[TOWN.COUNTRY] = b.[TOWN.COUNTRY]
group by [GIVEN.NAMES],[FAMILY.NAME],[DATE.OF.BIRTH],[POST.CODE],[STREET],[TOWN.COUNTRY]
having count(*) >= 1)
This query will return thousands of records but I'm generally interested in the record with a high count of exactly matching fields
Below is a table im working with. I would like to take the field from [Field1] column and move directly across to [Field2] column.
Results would be like this
Field2
Browser
com.android.browser
com.android.browser.BrowserActivity
Email
com.android.email
com.android.email.activity.Welcome
Phone
com.android.contacts
com.android.contacts.activities.PCUDialtactsActivity
Gallery
com.android.gallery3d
com.android.gallery3d.app.Gallery
Tắt mà n hình
com.katecca.screenofflockdonate
com.katecca.screenofflockdonate.MainHelper
Messaging
com.android.mms
com.android.mms.ui.ConversationList
Simple mode
com.pantech.app.skysettings.simplemode
com.pantech.app.skysettings.simplemode.simplemodesettingshrotcutActivity
This might do what you need:
SELECT iif(isnull(Field2), Field1, Field2) as [yourColumnTitle]
FROM yourTableName
Aside from this you'll need to add a column to the table datatype=YesNo and set it to true on the rows you want to affect, then you can
SELECT iif(NewColumn <> 0, Field1, Field2) as [yourColumnTitle]
FROM yourTableName
I want to produce a map that contains the original room ID and its new room ID equivalent for every room created.
Try using the "OUTPUT" clause with your insert statement. You can then map all of the inserted values and the keys that went with it to a different "mapping" table. Edit: I should add, this is all done in a SINGLE transaction, which makes the performance GREAT!
Insert Into TableA
(
Field1,
Field2,
Field3
)
Output Inserted.Field1, Field2, Field3, MappingID
Into MappingTable
Select Field1, Field2, Field3
From Rooms
Here's a link to the msdn site for the OUTPUT clause: http://msdn.microsoft.com/en-us/library/ms177564.aspx
Though I would suggest you to alter the table design and have a separate column each for New and Original site Id, but in present design I think you are looking for following:
SELECT
Name, #origSiteID, ControlsSiteNum, ControlsRoomNum, IsActive
FROM Rooms
WHERE SiteID = #newSiteID
I have one mdb table with the following structure:
Field1 Field2 Field3 Field4
A ...
B ...
I try to use a query to list all the different fields of row A and B in a result-set:
SELECT * From Table1
WHERE Field1 = 'A'
UNION
SELECT * From Table1
WHERE Field1 = 'B';
However this query has two problems:
it list all the fields including the
identical cells, with a large table
it gives out an error message: too
many fields defined.
How could i get around these issues?
Is it not easiest to just select all fields needed from the table, based on the Field1 value and group on the values needed?
So something like this:
SELECT field1, field2,...field195
FROM Table1
WHERE field1 = 'A' or field1 = 'B'
GROUP BY field1, field2, ....field195
This will give you all rows where field1 is A or B and there is a difference in one of the selected fields.
Oh and for the group by statement as well as the SELECT part, indeed use the previously mentioned edit mode for the query. There you can add all fields (by selecting them in the table and dragging them down) that are needed in the result, then click the 'totals' button in the ribbon to add the group by- statements for all. Then you only have to add the Where-clause and you are done.
Now that the question is more clear (you want the query to select fields instead of records based on the particular requirements), I'll have to change my answer to:
This is not possible.
(untill proven otherwise) ;)
As far as I know, a query is used to select records using for example the where clause, never used to determine which fields should be shown depending on a certain criterium.
One thing that MIGHT help in this case is to look at the database design. Are those tables correctly made?
Suppose you have 190 of those fields that are merely details of the main data. You could separate this in another table, so you have a main table and details table.
The details table could look something like:
ID ID_Main Det_desc Det_value
This way you can filter all Detail values that are equal between the two main values A and B using something like:
Select a.det_desc, a.det_value, b.det_value
(Select Det_desc, det_value
from tblDetails
where id_main = a) as A inner join
(Select Det_desc, det_value
from tblDetails
where id_main = a) as B
on A.det_desc = B.det_desc and A.det_value <> B.det_value
This you can join with your main table again if needed.
You can full join the table on itself, matching identical rows. Then you can filter on mismatches if one of the two join parts is null. For example:
select *
from (
select *
from Table1
where Field1 = 'A'
) A
full join
(
select *
from Table1
where Field1 = 'B'
) B
on A.Field2 = B.Field2
and A.Field3 = B.Field3
where A.Field1 is null
or B.Field1 is null
If you have 200 fields, ask Access to generate the column list by creating a query in design view. Switch to SQL view and copy/paste. An editor with column mode (like UltraEdit) will help create the query.