I am attempting to filter a table of user actions on a list of specific actions. For example, given the following data
+--------+--------------------------------------------------------------+
| UserId | UserAction |
+--------+--------------------------------------------------------------+
| 12345 | Account Creation Successful |
+--------+--------------------------------------------------------------+
| 23456 | Attempt to create duplicate account with email abc@email.com |
+--------+--------------------------------------------------------------+
| 34567 | Account Creation Unuccessful |
+--------+--------------------------------------------------------------+
| 45678 | Attempt to create duplicate account with email xyz@email.com |
+--------+--------------------------------------------------------------+
| 56789 | Email Sent |
+--------+--------------------------------------------------------------+
I want all rows where the UserAction
contains the strings “Account Creation” or “Attempt to create duplicate account”.
I was able to achieve this with the following Linq, but the query’s performance caused the webpage to timeout and blocked other queries to the table.
var actions = new HashSet<string>
{
"Account Creation",
"Attempt to create duplicate account"
};
using (var databaseContext = new DatabaseContext())
{
var logs = databaseContext.Actions.Where(log => actions.Any(a => log.UserAction.Contains(a)));
}
To optimize this, I wanted to use an entirely SQL solution. One way of doing so could be using multiple
WHERE [UserAction] LIKE 'Account Creation%' OR [UserAction] LIKE 'Attempt to create duplicate account%' OR
but I need to filter on many different actions, not just the two in this example, causing too long of a query with multiple OR LIKE
statements.
Finally, I would like to use something similar to
WHERE [UserAction] IN ('Account Creation', 'Attempt to create duplicate account')
but the problem is the list contains substrings which will be found in the UserAction column. It would be great if I could use the entire UserAction string in the list used by the IN
operator, but because some strings have variable data (like the email address), I need to match substrings.
So, what I am looking for is a way to achieve the hypothetical
WHERE ('Account Creation', 'Attempt to create duplicate account') IN [UserAction]
where a list of substrings can be matched on the values of a column in SQL.
Thanks for your time.
The following SQL can be used to reproduce the situation.
DROP TABLE IF EXISTS [MatchListOnList].[dbo].[Actions]
CREATE TABLE [MatchListOnList].[dbo].[Actions] (
UserId varchar(16),
UserAction varchar(128)
)
INSERT INTO [MatchListOnList].[dbo].[Actions] (
UserId,
UserAction
)
VALUES
(
'12345',
'Account Creation Successful'
),
(
'23456',
'Attempt to create duplicate account with email abc@email.com'
),
(
'34567',
'Account Creation Unsuccessful'
),
(
'45678',
'Attempt to create duplicate account with email xyz@email.com'
),
(
'56789',
'Email Sent'
),
(
'67890',
'Email Sent'
),
(
'78901',
'Email Sent'
)
Advertisement
Answer
I got it to work; it no longer times out and doesn’t block any other services.
I did this by building an SQL query and running it directly against the database.
var actions = new HashSet<string>
{
"Account Creation",
"Attempt to create duplicate account"
};
using (var databaseContext = new DatabaseContext())
{
var query = "SELECT * FROM [dbo].[Actions] WHERE [UserAction] LIKE ";
var queryStringActions = actions
.Select(action => $"'{action}%'");
query += $"{string.Join(" OR [UserAction] LIKE ", queryStringActions)}";
var logs = databaseContext.Database.SqlQuery<Entities.Action>(query).AsQueryable();
}
The resulting SQL query is as follows
SELECT * FROM [dbo].[Actions]
WHERE [UserAction] LIKE 'Account Creation%'
OR [UserAction] LIKE 'Attempt to create duplicate account%'