T-SQL Merge when matched not working - sql

I have a temp table containing email traffic data between domains as follows:
[EmailId|SendingDomainId|SendingDomainName|RecipientDomainId|RecipientDomainName]
[500|600|abc.com|700|pqr.com]
[501|601|def.com|701|stu.com]
[501|601|def.com|700|pqr.com]
[502|600|abc.com|700|pqr.com]
That is:
email id 500 was sent from abc.com to pqr.com (1 sender, 1 recipient)
email id 501 was sent from def.com to stu.com and pqr.com (1 sender, 2 recipients)
email id 502 was sent from abc.com to pqr.com (1 sender, 1 recipient)
I am trying to compile a report which contains totals of emails sent between domains, to produce the following:
[SendingDomainId|SendingDomainName|RecipientDomainId|RecipientDomainName|Total]
[600|abc.com|700|pqr.com|2]
[601|def.com|701|stu.com|1]
[601|def.com|700|pqr.com|1]
I am trying this MERGE statement but the UPDATE part is not working. I am ending up with a final table containing the same rows as the source table.
MERGE #DomainsChord_TrafficData as T
USING #DomainsChord_DomainEmails AS S
ON (S.SendingDomainId = T.SendingDomainId AND
S.RecipientDomainId = T.RecipientDomainId)
WHEN MATCHED THEN UPDATE
SET T.TotalEmails = T.TotalEmails+1
WHEN NOT MATCHED BY TARGET THEN
INSERT (SendingDomainId, SendingDomainName, RecipientDomainId,
RecipientDomainName, TotalEmails)
VALUES (S.SendingDomainId, S.SendingDomainName,
S.RecipientDomainId, S.RecipientDomainName, 1);
Table #DomainsChord_TrafficData is an empty temp table before the merge. After the merge, it ends up with the same data as the source table (#DomainsChord_DomainEmails)
Is anyone able to spot where i am doing wrong?
Thanks in advance

If the table is empty before hand, then there is no Match for the update to execute, it is a NOT MATCHED and therefore the insert runs.

You don't need a MERGE in your case. You need a simple SELECT with a GROUP BY clause as follows:
SELECT SendingDomainId, SendingDomainName, RecipientDomainId, RecipientDomainName
, COUNT(*) AS Total
FROM #DomainsChord_DomainEmails
GROUP BY SendingDomainId, SendingDomainName, RecipientDomainId, RecipientDomainName;
OUTPUT
SendingDomainId SendingDomainName RecipientDomainId RecipientDomainName Total
--------------- ----------------- ----------------- ------------------- -----------
600 abc.com 700 pqr.com 2
601 def.com 700 pqr.com 1
601 def.com 701 stu.com 1
A MERGE statement is to merge data from two a source into a target. If your target (#DomainsChord_TrafficData) is empty, all data from source (#DomainsChord_DomainEmails) ends up in the target as you described.
Reference: MSDN MERGE T-SQL

Related

How to make an exact match between Ids with one column in common?

I must confess I have no idea into to how properly ask this question but I'll try to do my best.
I have two tables (PROMO and DETAILED_PROMO) that are related by a forkeign key (ID_PROMO). The tables are as follow:
PROMO
--ID_PROMO
--DESCRIPTION
DETAILED_PROMO
--ID_DETAILED_PROMO
--ID_PROMO
--ID_SERVICE
When I create a new promo in the table PROMO it also creates one or several registers in the table DETAILED_PROMO with the different services associated to that promo. Something like this:
--------PROMO----------
ID_PROMO | DESCRIPTION
------------------------
id_promo1 | Promo 1
----------|-------------
id_promo2 | Promo 2
----------| ------------
id_promo3 | Promo 3
-----------DETAILED PROMO----------------------
ID_DETAILED_PROMO | ID_PROMO| ID_SERVICE
-------------------|---------|-----------------
id_detailed_promo1 |id_promo1| Id_Service1
-------------------|---------|-----------------
id_detailed_promo2 |id_promo1| Id_Service2
-------------------|---------|-----------------
id_detailed_promo3 |id_promo1| Id_Service3
-------------------|---------|-----------------
id_detailed_promo4 |id_promo2| Id_Service1
-------------------|---------|-----------------
id_detailed_promo5 |id_promo2| Id_Service2
-------------------|---------|-----------------
id_detailed_promo6 |id_promo2| Id_Service4
-------------------|---------|-----------------
id_detailed_promo7 |id_promo3| Id_Service1
-------------------|---------|-----------------
id_detailed_promo7 |id_promo3| Id_Service2
-------------------|---------|-----------------
id_detailed_promo7 |id_promo3| Id_Service3
-------------------|---------|-----------------
id_detailed_promo7 |id_promo3| Id_Service4
The rules of creating or updating a promo is that there cannot exist another promo with the exact numbers of services and the same Id_Service.
For example, if I try to delete from DETAILED_PROMO the Id_Service 4 from id_promo3, the Promo 3 would have the same numbers of services AND the same services of Promo 1 therefore deleting that Id_Service should not be allowed. If I delete Id_Service3 from id_promo3, the Promo 3 would have the same numbers of services AND the same services of Promo 2. BUT if I delete Id_Service1 from id_promo3, no other promos have the same services and the same number of services associated to it, so it should allow me to delete that register.
How can I validate this? If I want to delete a register, I am being given the ID_DETALED_PROMO and the ID_PROMO as parameters in the store procedure.
I think here is what you can do for checking , I used int for ids:
this query checks if there is the same number of serviceids with similar ids in each promo :
DECLARE #ID_promo INT = 3;
DECLARE #Id_Service INT = 4;
SELECT
d1.ID_promo
, COUNT(CASE WHEN d1.ID_Service = d2.ID_Service THEN 1 ELSE NULL END) equalcount
, COUNT(d1.id) totalcount
FROM
detailed_promo d1
LEFT JOIN detailed_promo d2
ON d1.id_Service = d2.Id_service
AND d2.ID_Service NOT IN (#Id_Service)
AND d2.ID_PROMO = #ID_promo
WHERE
d1.id_promo <> #ID_promo
GROUP BY
d1.ID_promo
HAVING
COUNT(CASE WHEN d1.ID_Service = d2.ID_Service THEN 1 ELSE NULL END) = COUNT(d1.id);
so If you want to to delete check you can do something like this
delete from detailed_promo where id = #ID_promo and id_service= #Id_Service and not exists (queryabove)
you also can use multiple serviceIds if you are deleting multiple service ids within one promo id
and If I'm not mistaken the same rule applies for insert and update, so the same query can be used for Insert/Update as well.

SQL update from one table to another based on column match on Apache Derby

N.B. I'm looking for a solution working on Apache Derby
I have two sql tables. The first, called links, contains links of the form
SOURCE | TARGET
1234 | 456
15 | 625
... | ...
where the integers here are the ids of the objects being linked. The second table, called redir, contains redirection links:
ID | REDIRTARGET
456 | 521
198 | 140
... | ...
If the target of a link is in the id column of redir, then it must be redirected to the object of id redirtarget.
Now, I would like to update my links table by replacing all targets which are in the id column of redir by the associated redirtarget.
For example, given the two tables above (without ellipses), the update instruction would replace 456 with 521 in the target column of links.
I haven't been able to find a working instruction on my own. I've tried things like
UPDATE links,redir SET target=redirtarget WHERE id=target
but that won't compile (specifically, derby points out at the comma between UPDATE and SET). Help anybody ?
You can't specify multiple tables in an UPDATE list.
If ID in the redir table is unique, you should be able do something like this:
update links
set target = (select redirtarget
from redir
where redir.id = links.target)
where exists (select *
from redir
where redir.id = links.target);
The where condition ensures that only rows in links are updated where there is actually a match in the redir table.

Select items where count in another field matches (not updatable)

Here I am trying to get the record for my products where the # swab location in Main table matches the count of swab locations in swab Table and Users can checked off the Y/N to verify that the description of the locations are correct.
Here is the example of my 2 tables.
tblMainEquipment
Asset_ID EquipmentName Num_SwapLocations Verified
234 Saijimon 2 N
235 Pasquale 3 N
tblMainSwapLocations
Asset_ID Swap_location
234 Particle Cannon
234 RailGun
235 Particle Cannon
I use the following query to count the number of records, i avoided using a having query to combine both tables since it is not updatable.
qryMainSwapLocationCount
SELECT MSL.Asset_ID, Count(Asset_ID) AS [Count]
FROM tblMainSwapLocation AS MSL
GROUP BY MSL.Asset_ID;
This will give me the result of
qryMainSwapLocationCount
Asset_ID count
234 2
234 1
I used the following as a record source for my form to allow users to verify the inputs.
SELECT MEQ.Asset_ID, MEQ.Equipment_Name,MEQ.Num_swapLocations MEQ.Verified
FROM tblMainEquipment AS MEQ, qryMainSwapLocationCount AS MSLC
WHERE (((MEQ.Asset_ID)=[MSLC].[Asset_ID]) AND ((MEQ.Num_SwapLocations)=[MSLC].[Count]);
This result would be
tblMainEquipment
Asset_ID EquipmentName Num_SwapLocations Verified
234 Saijimon 2 N
However this record set is not editable. Is there any reasons for this?
I think you should put your table tblMainEquipment as your recordsource and bring all the fields from that on to your form:
Then insert an unbound textbox (perhaps close to your Num_SwapLocations field for easy comparison):
Then in this new textbox, put the following in the ControlSource:
=DCount("ASSET_ID","tblMainSwapLocations","ASSET_ID=" & [Asset_ID])
Then open your form and it should count the number of records in table tblMainSwapLocations that have the same Asset_ID as the record currently showing:
You'll then be able to update the Verified field in your tblMainEquipment table.

Selecting rows using multiple LIKE conditions from a table field

I created a table out of a CSV file which is produced by an external software.
Amongst the other fields, this table contains one field called "CustomID".
Each row on this table must be linked to a customer using the content of that field.
Every customer may have one or more set of customIDs at their own discretion, as long as each sequence starts with the same prefix.
So for example:
Customer 1 may use "cust1_n" and "cstm01_n" (where n is a number)
Customer 2 may use "customer2_n"
ImportedRows
PKID CustomID Description
---- --------------- --------------------------
1 cust1_001 Something
2 cust1_002 ...
3 cstm01_000001 ...
4 customer2_00001 ...
5 cstm01_000232 ...
..
Now I have created 2 support tables as follows:
Customers
PKID Name
---- --------------------
1 Customer 1
2 Customer 2
and
CustomIDs
PKID FKCustomerID SearchPattern
---- ------------ -------------
1 1 cust1_*
2 1 cstm01_*
3 2 customer2_*
What I need to achieve is the retrieval of all rows for a given customer using all the LIKE conditions found on the CustomIDs tables for that customer.
I have failed miserably so far.
Any clues, please?
Thanks in advance.
Silver.
To use LIKE you must replace the * with % in the pattern. Different dbms use different functions for string manipulation. Let's assume there is a REPLACE function available:
SELECT ir.*
FROM ImportedRows ir
JOIN CustomIDs c ON ir.CustomID LIKE REPLACE(c.SearchPattern, '*', '%')
WHERE c.FKCustomerID = 1;

SQL filter search according to multiple column values

I am dealing with one table(3+ million rows,SQL Server)
I need to filter results according to the two columns below:
<code>
...FromID| ToID |Column5|....
...1001 2001
...1002 2020
...1003 5000
...1001 3000
...2001 1001
</code>
Now User1 can access records with FromID or ToId 1001.
FromID|ToID
1001|2001
1001|3000
2001|1001
User2 can access records with FromID or ToID 1002,1003,3000
FromID|ToID
1002|2020
1003|5000
1001|3000
What is the most efficient way to do this ?
Do i need to create a view for each user ?(this is working on enterprise,user count will be
max 100 )
Thanks.
PS. My very first question. O.o
Your access criteria seem to be fairly arbitrary. User1 gets 1001, user2 gets 1002, 1003, and 3000, and I assume users 3 through 99 have arbitrary access as well. In that case, I recommend that you create a table, call it useraccess for this example:
user |accessID
---------------
user1|1001
user2|1002
user2|1003
user2|3000
... |...
Now when you want to know what rows a user has, you can do this:
SELECT t.FromID, t.ToID, [[other columns you care about]]
FROM yourtable t
JOIN useraccess a ON t.FromID = a.accessID OR t.ToID = a.accessID
WHERE a.user = 'user2'
You can either run that query dynamically or you can create a view based on it. The usual tradeoffs between views and direct queries will apply as usual.
Edit: I just saw your note that you already have a UserRights table, so you already have step 1 completed.