How to select records which do not have rows with dates falling in the current week - sql

I'm moving a linq query to ado and can't seem to get the correct syntax for achieving my desired results.
I have a simple setup where user's have associated actions. I want to select users that are not following me and have had no action records on file for the current week.
Here is the equivalent linq query I'm trying to convert (note these are different table names but with the same exact schema)
var users = context.IG_Cats_Users.Where(p => p.IsFollowing == false
& p.IsRequested == false &
!p.IG_Cat_Actions.Any(
a =>
DbFunctions.TruncateTime(a.Date) >=
first.Date
&
DbFunctions.TruncateTime(a.Date) <=
last.Date))
.Take(numOfUsers);
Here is my query so far
var qry = "SELECT Id FROM Users "
+ "INNER JOIN Actions ON Users.Id = Actions.UserId "
+ "WHERE Users.IsFollowing = 0 AND Users.IsRequested = 0 AND IF NOT EXISTS ("
I figured I'd try IF NOT EXISTS EXISTS
but per every example they run a subquery in the clause. I want to make sure any actions being searched are associated with the user from the first part of the query but I can't figure out how to work it out in TSQL
EDIT
Concerning the dates: I already have the two date values being created in code which I am passing to the function. It's computed in C#

Something like this:
SELECT u.Id
FROM Users u
WHERE u.IsFollowing = 0 AND u.IsRequested = 0 AND
NOT EXISTS (SELECT 1
FROM Actions a
WHERE u.Id = a.UserId
);

Related

Check in T-SQL whether certain value sets exist in a related table

I have following tables:
User - userId, userName, ...
Settings - settingId, userId, settingKey, settingValue
for example for userId = 123, I might have:
settingId: 1
userId: 123
settingKey: "allowClient"
settingValue: "0"
settingId: 2
userId: 123
settingKey: "allowAccess"
settingValue: "1"
Then for example how can I query for all users that have settingValue of "0" corresponding to settingKey of "allowClient" and settingValue of "1" corresponding to settingKey of "allowAccess"? Sometimes the settingKey and settingValue that I'm looking for might not even be there for a particular user, in which case, I would just want to ignore those users.
My "attempt":
select * from User u inner join Settings s on u.userid = s.userid
where s.settingKey = 'allowClient and s.settingValue = '0'
and s.settingKey = 'allowAccess' and s.settingValue = '1'
this doesn't work for obvious reason because it's putting AND on all the conditions. I'm not aware of any sql construct that can get around this and allow me to just say what I actually want.
Your first attempt doesn't work because the WHERE clause check each row one at a time. And no single row fulfils all of those conditions at once.
So, you could use an EXISTS() check on each of the two keys, for a very literal expression of your problem...
SELECT
user.*
FROM
user
WHERE
EXISTS (
SELECT *
FROM settings
WHERE userId = user.userId
AND settingKey = 'allowClient'
AND settingValue = '0'
)
AND
EXISTS (
SELECT *
FROM settings
WHERE userId = user.userId
AND settingKey = 'allowAccess'
AND settingValue = '1'
)
Depending on data characteristics, you may benefit from a single sub-query instead of two EXISTS() checks.
This is closer to what you were trying to do.
Filter to get two rows per user (using OR instead of AND)
Aggregate back down to a single row and check if both conditions were met
(But I'd go with two EXISTS() first, and let the optimiser do its work.)
WITH
matching_user
(
SELECT
userId
FROM
settings
WHERE
(settingKey = 'allowClient' AND settingValue = '0')
OR
(settingKey = 'allowAccess' AND settingValue = '1')
GROUP BY
userId
HAVING
COUNT(DISTINCT settingKey) = 2 -- DISTINCT only needed if one user has the same key set twice
)
SELECT
user.*
FROM
user
INNER JOIN
matching_user
ON user.userId = matching_user.userId
Finally, you could just join twice, which is functionally similar to the double-exists check, but shorter code, though not always as performant.
SELECT
user.*
FROM
user
INNER JOIN
settings AS s0
ON s0.userId = user.userId
AND s0.settingKey = 'allowClient'
AND s0.settingValue = '0'
INNER JOIN
settings AS s1
ON s1.userId = user.userId
AND s1.settingKey = 'allowAccess'
AND s1.settingValue = '1'
Using the two different aliases prevents ambiguity (which would cause an error).
It does assume that the joins will only ever find 0 or 1 rows, if they can find many, you get duplication. EXISTS() doesn't have that problem.

SQL MAX not returning unique records

I'm using the SQL MAX on a field in my db called "Date_Created", essentially i use it to bring back the most recent record for a particular user. It works fine for all user records that have higher count than 1 but when a user only has one record SQL MAX does not return a record" Can anyone advise what i'm doing wrong ?
code:
"SELECT CP_Score.Credit_Score "
. "FROM CP_Score "
. "INNER JOIN phpro_users ON CP_Score.ID_No=phpro_users.ID_No "
. "WHERE phpro_users.User_ID = $userloggedin "
. " AND CP_Score.Date_Created = (SELECT MAX(CP_Score.Date_Created) "
. " FROM CP_Score)";
SELECT CP_Score.Credit_Score
FROM CP_Score
INNER JOIN phpro_users ON CP_Score.ID_No=phpro_users.ID_No
WHERE phpro_users.User_ID = $userloggedin
AND CP_Score.Date_Created = (SELECT MAX(cps2.Date_Created)
FROM CP_Score cps2
WHERE cps2.ID_No=phpro_users.ID_No)
If you are looking for one record, you can limit the result set to a single record. In ANSI/ISO standard syntax:
SELECT s.Credit_Score
FROM CP_Score s INNER JOIN
phpro_users u
ON s.ID_No = u.ID_No
WHERE u.User_ID = $userloggedin
ORDER BY Date_Created DESC
FETCH FIRST 1 ROW ONLY;
Some databases express the FETCH FIRST clause differently -- SELECT TOP (1) or LIMIT are common.

using criteria in an update query involving a join

I'm using MS Access
The SQL below updates the CurrNumTees field in the Parent tblContact records with the number of tblTorTee records that have an end date (which is not the ultimate effect I am aiming for, but I provide it as a starting point.
UPDATE tblContact
INNER JOIN tblTorTee ON tblContact.ContactId = tblTorTee.TorId
SET tblContact!CurNumTees = DCount("[tblTorTee.EndDate]",
"tbltortee","Torid = " & [ContactId]);
I need to update the CurrNumTees field with the number of records in tblTorTee that do not have an EndDate, in other words, that field is blank. I’ve tried using WHERE and HAVING and IS NULL in various combinations and locations, but without success. Could you help point me in the right direction?
The MS Access COUNT function does not count nulls, so I think you have to do this in two stages.
Firstly create a query like this:
SELECT TorId, IIF(ISNULL(EndDate),1,0) AS isN
FROM tblTorTee
WHERE EndDate IS NULL;
And save it as QryEndDateNull
Now you can run an Update Query like this:
UPDATE tblContact
SET tblContact.CurNumTees = DSUM("IsN","QryEndDateNull","TorId = " & [ContactID]);
Saving calculated data (data dependent on other data) is usually a bad design, especially aggregate data. Should just calculate when needed.
Did you try the IS NULL criteria within the DCount()?
UPDATE tblContact Set CurNumTees = DCount("*", "tblTorTee", "EndDate Is Null AND TorId = " & [ContactId]);

Can nested query in JPQL access outer query

So I'm curious if a nested SELECT can reference it's outer SELECT in order to compare values. I haven't been able to test or see many examples on this topic.
As an example, I'm trying to write a query to select all Clothes rows that has a tag (some number) that is within a given list and has the highest time that is prior to given time (which is total number of seconds). The query in question is below:
SELECT c FROM Clothes c WHERE c.tag IN :tagList
AND (c.timeOfSale = (SELECT MAX(n.timeOfSale) FROM Clothes k
WHERE (c.tag = k.tag) AND (k.timeOfSale) < (:time))) GROUP BY c.tag
Is the comparison c.tag = k.tag valid? If not, is there an alternative?
#Query("SELECT b FROM Business b WHERE b <> :currentBusiness "
+ "and exists "
+ "(Select i from InterestMaster i, BusinessInterest bI where bI.interestMaster = i and bI.business = b"
+ "and i in (:userInterests))")
Page<Business> getCommunityBusiness(#Param("currentBusiness") Business currentBusiness, #Param("userInterests") List<InterestMaster> userInterests,Pageable pageable);
I am using the above JPQL and its working fine. So yes nested query can access outer query.
Yes. They're called correlated queries, where the subquery is evaluated for each row of outer query.

How to mimic GROUP BY in Cassandra

Is it possible to mimic GROUP BY functionality from SQL using Cassandra? If yes, please provide a short example that does that.
I was thinking, if the groups where known a head of time, then a loop of multiple async queries on each different group would have a similar effect.
For example group by on months.
for month in range(1,12):
query = "select * from table where col_month = " + month
session.execute_async(query)
If this isn't an option you would have to first select what you are grouping on and take the set of all data.
query = "select col_month from table"
rows = session.execute(query)
values = Set()
for row in rows:
values.add(row)
query = "select * from table where col_month = "
for value in values:
session.execute_async(query+value)