Concatenating fields - sql

This is an MS Access (2010) script.
I am trying to concatenate 2 fields of a single table for 2 tables. Then I want to delete the associated record in one of the table if the concatenated field is equal in both tables (means this is a duplicate).
I know how to do that in VBA by looping through the records but I want to do that in SQL since the tables may quickly hold more than 50000 records which means the loop would go 2,500,000,000 times.
I though I could create a 2 SELECT statement in order to create the concatenated fields for both tables. The SELECT Statements will also display the ID of the underlying tables. Then I would delete the record in the appropriate table using the ID.
These are my Select statements:
SELECT [Tick] & [Div_ex_date] AS Expr2, tblBbgDivData.ID
FROM tblBbgDivData
GROUP BY [Tick] & [Div_ex_date], tblBbgDivData.ID;
And
SELECT [Security_Name] & [Div_ex_date] AS Expr1, tblArchiveBbgDivData.ID
FROM tblArchiveBbgDivData
GROUP BY [Security_Name] & [Div_ex_date], tblArchiveBbgDivData.ID;
This is my DELETE Statement:
DELETE tblArchiveBbgDivData.*
FROM (tblArchiveBbgDivData
INNER JOIN qselUniqueID_Archive ON tblArchiveBbgDivData.ID = qselUniqueID_Archive.ID)
INNER JOIN qselUniqueID_BbgDiv ON qselUniqueID_Archive.Expr1 = qselUniqueID_BbgDiv.Expr2
WHERE (((tblArchiveBbgDivData.ID)=[qselUniqueID_Archive].[ID])
AND ((qselUniqueID_Archive.Expr1)=[qselUniqueID_BbgDiv].[Expr2]));
When I hit Datasheet view, the relevant records are displayed but when I hit Run I get "Could not delete from specified tables". Any idea how I can change that?

Access does not work well with JOINs in a DELETE statement. You may be better off with an IN:
DELETE tblArchiveBbgDivData.*
FROM (tblArchiveBbgDivData
WHERE tblArchiveBbgDivData.ID IN
(SELECT qselUniqueID_Archive.ID
FROM qselUniqueID_Archive )
INNER JOIN qselUniqueID_BbgDiv
ON qselUniqueID_Archive.Expr1 = qselUniqueID_BbgDiv.Expr2
);
Note that your WHERE is redundant because you use the same expression in your JOIN syntax.

Related

Best way to combine two tables, remove duplicates, but keep all other non-duplicate values in SQL

I am looking for the best way to combine two tables in a way that will remove duplicate records based on email with a priority of replacing any duplicates with the values in "Table 2", I have considered full outer join and UNION ALL but Union all will be too large as each table has several 1000 columns. I want to create this combination table as my full reference table and save as a view so I can reference it without always adding a union or something to that effect in my already complex statements. From my understanding, a full outer join will not necessarily remove duplicates. I want to:
a. Create table with ALL columns from both tables (fields that don't apply to records in one table will just have null values)
b. Remove duplicate records from this master table based on email field but only remove the table 1 records and keep the table 2 duplicates as they have the information that I want
c. A left-join will not work as both tables have unique records that I want to retain and I would like all 1000+ columns to be retained from each table
I don't know how feasible this even is but thank you so much for any answers!
If I understand your question correctly you want to join two large tables with thousands of columns that (hopefully) are the same between the two tables using the email column as the join condition and replacing duplicate records between the two tables with the records from Table 2.
I had to do something similar a few days ago so maybe you can modify my query for your purposes:
WITH only_in_table_1 AS(
SELECT *
FROM table_1 A
WHERE NOT EXISTS
(SELECT * FROM table_2 B WHERE B.email_field = A.email_field))
SELECT * FROM table_2
UNION ALL
SELECT * FROM only_in_table_1
If the columns/fields aren't the same between tables you can use a full outer join on only_in_table_1 and table_2
try using a FULL OUTER JOIN between the two tables and then a COALESCE function on each resultset column to determine from which table/column the resultset column is populated

Insert Into where not exists from specific category

I have a table that contains several repair categories, and items that are associated with each repair category. I am trying to insert all the standard items from a specific repair category that don't already exist into a Details table.
TblEstimateDetails is a join table for an Estimate Table and StandardItem Table. And TblCategoryItems is a join table for the Repair Categories and their respective Standard Items.
For example in the attached image, Left side are all the Standard Items in a Repair Category, and Right side are all the Standard Items that are already in the EstimateDetails table.
Standard Items All vs Already Included
I need to be able to insert the 6 missing GUIDS from the left, and into the table on the right, and only for a specific estimate GID.
This is being used in an Access VBA script, which I will translate into the appropriate code once I get the sql syntax correct.
Thank you!
INSERT INTO TblEstimateDetails(estimate_GID, standard_item_GID)
SELECT
'55DEEE29-7B79-4830-909C-E59E831F4297' AS estimate_GID
, standard_item_GID
FROM TblCategoryItems
WHERE repair_category_GID = '32A8AE6D-A512-4868-8E1A-EF0357AB100E'
AND NOT EXISTS
(SELECT standard_item_GID
FROM TblEstimateDetails
WHERE estimate_GID = '55DEEE29-7B79-4830-909C-E59E831F4297');
Some things to try: 1) simplify to a select query to see if it selects the right records, 2) use a NOT IN statement instead of NOT EXISTS. There's no reason NOT EXISTS shouldn't work, I'd just try a different way if it isn't working.
SELECT '55DEEE29-7B79-4830-909C-E59E831F4297' AS estimate_GID,
standard_item_GID
FROM TblCategoryItems
WHERE repair_category_GID = '32A8AE6D-A512-4868-8E1A-EF0357AB100E'
AND standard_item_GID NOT IN
(SELECT standard_item_GID FROM TblEstimateDetails
WHERE estimate_GID = '55DEEE29-7B79-4830-909C-E59E831F4297');
Got it figured out. Access needs the subquery to be correlated to main query to work. So I set the WHERE clause in the subquery to equal the matching column in the main query. And I had to join the Estimates table so that it picked only the items in a specific estimate.
SELECT
'06A2E0A9-9AE5-4073-A856-1CCE6D9C48BB' AS estimate_GID
, CI.standard_item_GID
FROM TblCategoryItems CI
INNER JOIN TblEstimates E ON CI.repair_category_GID=E.repair_category_GID
WHERE E.repair_category_GID = '15238097-305E-4456-B86F-3787C9B8219B'
AND NOT EXISTS
(SELECT ED.standard_item_GID
FROM TblEstimateDetails ED
WHERE E.estimate_GID=ED.estimate_GID
);

Cannot update a table using a simple inner join

I have 2 tables in access 2007.
See attached picture to see the structure of the tables and the expected result.
I am trying to update the quantity field (ITQTY) in TABLE_BLNC by summarizing all the quantity field (LOCQTY) from TABLE_DTL for same items (LOITNBR=ITNBR).
In TABLE_BLNC, the item is unique while in TABLE_DTL, the item can be in multiple records.
My query is:
UPDATE TABLE_BLNC INNER JOIN
(
SELECT LOITNBR, Sum(LOCQTY) AS SumOfLOCQTY FROM TABLE_DTL GROUP BY LOITNBR) AS DTL
ON TABLE_BLNC.ITNBR=DTL.LOITNBR SET TABLE_BLNC.ITQTY = DTL.SumOfLOCQTY;
I am getting the error:
Operation must use an updateable query.
Domain Aggregate functions can be useful when Access complains that an UPDATE is not updateable. In this case, use DSum() ...
UPDATE TABLE_BLNC
SET ITQTY =
DSum("LOCQTY", "TABLE_DTL", "LOITNBR='" & ITNBR & "'");
Index TABLE_DTL.LOITNBR for optimum performance.
One of the great annoyances of Access SQL is its inability to update a table from an non-updatable source. Non-updatable sources include read-only links to ODBC tables, and GROUP BY (summary) queries.
What I always do is:
Copy the structure of TABLE_BLNK to a temp table: TABLE_BLNK_temp.
In your code, first delete the temp:
DELETE * FROM TABLE_BLNK_temp;
Insert the result of your summary query into temp:
INSERT INTO TABLE_BLNK_temp (ITNBR, ITQTY)
SELECT LOITNBR, Sum(LOCQTY) AS SumOfLOCQTY
FROM TABLE_DTL GROUP BY LOITNBR;
Update TABLE_BLNK from TABLE_BLNK_temp:
UPDATE TABLE_BLNC INNER JOIN TABLE_BLNK_temp AS t
ON TABLE_BLNC.ITNBR = t.ITNBR
SET TABLE_BLNC.ITQTY = t.ITQTY;
While it is an extra step or two, this approach:
Always works
Is more performant than Domain Aggregate functions for larger datasets

SQL- make all rows show a column value if one of the rows has it

I have an SQL statement for a PICK sheet that returns the header/detail records for an order.
One of the fields in the SQL is basically a field to say if there are dangerous goods. If a single product on the order has a code against it, then the report should display that its hazardous.
The problem I am having is that in the SQL results, because I am putting the code on the report in the header section (and not the detail section), it is looking for the code only on the first row.
Is there a way through SQL to basically say "if one of these rows has this code, make all of these rows have this code"? I'm guessing a subselect would work here... the problem is, is that I am using a legacy system built on FoxPro and FoxPro SQL is terrible!
EDIT: just checked and I am running VFP8, subqueries in the SELECT statement were added in FVP9 :(
SELECT Header.HeaderId, Header.HeaderDescription,
Detail.DetailId, Detail.DetailDescription, Detail.Dangerous,
Danger.DangerousItems
FROM Header
INNER JOIN Detail ON Header.HeaderId = Detail.HeaderId
LEFT OUTER JOIN
(SELECT HeaderId, COUNT(*) AS DangerousItems FROM Detail WHERE Dangerous = 1 GROUP BY HeaderId) Danger ON Header.HeaderId = Danger.HeaderId
If Danger.DangerousItems > 0 then something is dangerous. If it is Null then nothing is dangerous.
If you can't do nested queries, then you should be able to create a view-like object (called a query in VFP8) for the nested select:
SELECT HeaderId, COUNT(*) AS DangerousItems FROM Detail WHERE Dangerous = 1 GROUP BY HeaderId
and then can you left join on that?
In VFP 8 and earlier, your best bet is to use three queries in a row:
SELECT Header.HeaderId, Header.HeaderDescription,
Detail.DetailId, Detail.DetailDescription, Detail.Dangerous,
Danger.DangerousItems
FROM Header
INNER JOIN Detail ON Header.HeaderId = Detail.HeaderId
INTO CURSOR csrDetail
SELECT HeaderId, COUNT(*) AS DangerousItems
FROM Detail
WHERE Dangerous
GROUP BY HeaderId
INTO CURSOR csrDanger
SELECT csrDetail.*, csrDanger.DangerousItems
FROM csrDetail.HeaderID = csrDanger.HeaderID
INTO CURSOR csrResult

Avoiding join in MS Access delete query

I am trying to create a delete query to remove records from one table, based on whether or not one of the field exists in another master table. The situation is that I am importing new records into a database, but I want to remove the records that have already been imported, i.e. that already have an account in the master table. The field I need to join on, however is not equal: it is prefixed with a constant three letter code XYZ.
tbl_to_import.Account master_table.Account
123456 XYZ.123456
345678 XYZ.345678
To avoid using a join in the delete query I tried the following:
Delete tbl_to_import.*
From tbl_to_import
Where Exists( Select master_table.Account From master_table
Where master_table.Account = ("XYZ."& tbl_to_import.Account) ) = True;
However, the query gets hung up in Access. I'm not sure what I'm doing incorrectly. I don't get an error message, but the query runs without producing anything and I eventually stop it. In this situation, tbl_to_import has 2,700 records and master_table has 50,000 records. Additionally, I am connecting to the master_table via ODBC.
Originally, I constructed two queries using a join to perform the delete. tbl_to_import.Account has a primary key called ID. One query, qry_find_existing_accounts, located the ID numbers in tbl_to_import for which there exists a corresponding account in master_table.Account:
SELECT DISTINCTROW tbl_to_import.ID AS DELETEID
FROM tbl_to_import LEFT JOIN master_table
ON ("XYZ."& tbl_to_import.Account) = master_table.Account
WHERE ((("XYZ." & [Account])=[master_table].[Account]));
Then I used this query to construct the delete query:
DELETE DISTINCTROW tbl_to_import.*, tbl_to_import.ID
FROM tbl_to_import RIGHT JOIN qry_find_existing_accounts
ON tbl_to_import.ID =qry_find_existing_accounts.DELETEID
WHERE (((tbl_to_import.ID)=[qry_find_existing_accounts].[DELETEID]));
The query qry_find_existing_accounts worked fine; however, when I tried to run the second query to delete, I got the error: Could not delete from specified tables. Typically, when I get this error, it is because I have not selected unique records only, however, I used DISTINCTROW in both queries.
Any ideas what I am doing wrong and how I can accomplish what I need to do?
I'd go with a simpler nested SQL statement:
Delete tbl_to_import.*
From tbl_to_import
Where "XYZ." & tbl_to_import.Account In
(Select master_table.Account From master_table);
This should be fairly fast, especially if your Account fields are indexed.
I think you can simplify the query; delete based on the ID, where the IDs are in the query:
DELETE * FROM tbl_to_import
WHERE tbl_to_import.ID IN (
SELECT DISTINCT [DELETED] FROM qry_find_existing_accounts
)