Comparing "queries" and then saving the result for new select statement - sql

Iam trying to make a query that will check if a user is logged in or not.
The data is stored as 2 seperate rows one is called "in", when a users logs in and the other "out". I then need to find all people currently logged in but not logged out. so what ive tried is comparing the two select statement. This gives me the name(UNILOGIN) of all the people currently logged in and not out:
select UNILOGIN from timereg where date = CONVERT(DATE,GETDATE(),110) and CHECKEDIN = 'IND'
except
select UNILOGIN from timereg where date = CONVERT(DATE,GETDATE(),110) and CHECKEDIN = 'UD'
I then need to find their top 1 time, when they checked in. How would one make a statement that could get result in in one query string? If possible at all. something like:
SELECT TOP 1 UNILOGIN, TIME from TIMEREG where UNILOGIN = "result of query"
Tell me if i need to elaborate.

Aggregate. Get one result row per unilogin, make sure it has an 'IND' record and no 'UD' record and select the maximum login time for the date in question.
select unilogin, max(time)
from timereg
where date = convert(date, getdate(), 110)
and checkedin in ('IND', 'UD')
group by unilogin
having count(case when checkedin = 'IND' then 1 end) > 0
and count(case when checkedin = 'UD' then 1 end) = 0;

Related

<= less than equal to does't work as expected for sequilize query in nodejs

I have the following query in sequilize.js
const [results] = await sequelize.query(`select DISTINCT ON (variant_id) variant_id, Count(wl) as count, pds.name AS name,
CASE
WHEN pvs.name is NULL THEN pds.name
ELSE pvs.name
END
as variant_name,
im.url as img_url
from wish_lists as wl
LEFT JOIN products AS pds ON pds.id = wl.product_id
LEFT JOIN images as im on im.product_id = wl.product_id
LEFT JOIN product_variants as pvs ON pvs.id = wl.variant_id
where wl.created_at >= '${startDate}' AND wl.created_at <= '${endDate}' AND wl.tenant_id=${merchant_id}
group by ( variant_id, pds.name, im.url, pvs.name) LIMIT 100 OFFSET 0`)
The problem is if today is the 20th and i have products in the db that are selected on the 20th the query does't include those even though i have <= for the endDate, why is that ?
So why is the same day entries not being selected ?
Firstly, take a look at timezone of datetime data in database and in query param.
Secondly, created_at is the timestamp, which contain Time data (for example 2019-12-20T01:20:30.000Z). Then, your query param ${endDate} is just Date data only, it will append time = 0 (which is 00:00:00.000) before the comparison.
So the comparison would look like:
2019-12-20T01:20:30.000Z <= 2019-12-20T00:00:00.000Z
And the result is false, then it cannot be selected.

Need to add a subquery or something else to get a record from repeated rows?

I have the following code:
SELECT CONTRACT_QUOTE_ID,COUNT(CONTRACT_QUOTE_ID )
FROM CONTRACT_QUOTE
GROUP BY CONTRACT_QUOTE_ID
HAVING COUNT(CONTRACT_QUOTE_ID) > 1
Which basically shows the ids and the amount of time repated. But on each id there's a field that is the "CONTRACT_QUOTE_NO", but I don't know how to show them.
I've tried to do a subquery, but failed hard at it. Here's the code :
SELECT c1.CONTRACT_QUOTE_ID, c1.CONTRACT_QUOTE_NO, COUNTING = (SELECT COUNT(c2.CONTRACT_QUOTE_ID)
FROM CONTRACT_QUOTE c2
WHERE c1.CONTRACT_QUOTE_ID = c2.CONTRACT_QUOTE_ID)
FROM CONTRACT_QUOTE c1
GROUP BY c1.CONTRACT_QUOTE_ID,c1.CONTRACT_QUOTE_NO
HAVING COUNTING > 1
What could i do?

Trying to grab data from two columns and format them properly

So I have a database here with a table that lists off whether or not certain processes have failed. There are two columns, IsProcessed, and IsFailed. A failed process can still be considered processed if the error was handled, but I still need to recognize that it failed. They're both bit values, and so I have to try and grab and separate them despite that they may depend on one another. After they've been separated out, I need to count the relative successes and relative failures.
I utilize an AND statement in my WHERE clause to try and separate out the successes from the failures. I honestly have no idea where to go from here.
SELECT CAST(PQ.ProcessedDate AS Date) AS Date, COUNT(PQ.IsProcessed) AS Successes
FROM PQueue PQ
WHERE PQ.ProcessDate BETWEEN '2019-10-1' AND '2019-10-31' AND PQ.IsFailed = 0 AND PQ.IsProcessed = 1
GROUP BY CAST(PQ.ProcessDate AS Date)
ORDER BY CAST(PQ.ProcessDate AS Date) ASC
Because a failed process can still be processed in the system, we have to do a check first to try and grab the data that was processed but didn't flag a failure. Now I need to try and find a way to not exclude the failures, but include them and place them in a group. I can do the group part, but I'm relatively new to SQL so I don't know whether or not I can place something in an IF statement somewhere or try to use variables to get this done. Thank you in advance.
You seem to want conditional aggregation:
SELECT CAST(PQ.ProcessedDate AS Date) AS Date,
SUM(CASE WHEN PQ.IsFailed = 0 AND PQ.IsProcessed = 1 THEN 1 ELSE 0 END) as Successes,
SUM(CASE WHEN PQ.IsFailed = 1 AND PQ.IsProcessed = 1 THEN 1 ELSE 0 END) as Fails
FROM PQueue PQ
WHERE PQ.ProcessDate BETWEEN '2019-10-1' AND '2019-10-31'
GROUP BY CAST(PQ.ProcessDate AS Date)
ORDER BY CAST(PQ.ProcessDate AS Date) ASC
If SQL Server then maybe a CASE statement would help you out.
eg
SELECT ...........
CASE
WHEN IsFailed = 1 AND IsProcessed = 1 THEN "Processed But Failed"
WHEN IsFailed = 0 AND IsProcessed = 0 THEN "Not Processed"
WHEN IsFailed = 0 AND IsProcessed = 1 THEN "Processed Succesfully"
WHEN IsFailed = 1 AND IsProcessed = 0 THEN "Failed"
END as REsult

SubQuery Aggregates in ActiveRecord

I'm trying to avoid using straight up SQL in my Rails app, but need to do a quite large version of this:
SELECT ds.product_id,
( SELECT SUM(units) FROM daily_sales WHERE (date BETWEEN '2015-01-01' AND '2015-01-08') AND service_type = 1 ) as wk1,
( SELECT SUM(units) FROM daily_sales WHERE (date BETWEEN '2015-01-09' AND '2015-01-16') AND service_type = 1 ) as wk2
FROM daily_sales as ds group by ds.product_id
I'm sure it can be done, but i'm struggling to write this as an active record statement. Can anyone help?
If you must do this in a single query, you'll need to write some SQL for the CASE statements. The following is what you need:
ranges = [ # ordered array of all your date-ranges
Date.new(2015, 1, 1)..Date.new(2015, 1, 8),
Date.new(2015, 1, 9)..Date.new(2015, 1, 16)
]
overall_range = (ranges.first.min)..(ranges.last.max)
grouping_sub_str = \
ranges.map.with_index do |range, i|
"WHEN (date BETWEEN '#{range.min}' AND '#{range.max}') THEN 'week#{i}'"
end.join(' ')
grouping_condition = "CASE #{grouping_sub_str} END"
grouping_columns = ['product_id', grouping_condition]
DailySale.where(date: overall_range).group(grouping_columns).sum(:units)
That will produce a hash with array keys and numeric values. A key will be of the form [product_id, 'week1'] and the value will be the corresponding sum of units for that week.
Simplify your SQL to the following and try converting it..
SELECT ds.product_id,
, SUM(CASE WHEN date BETWEEN '2015-01-01' AND '2015-01-08' AND service_type = 1
THEN units
END) WK1
, SUM(CASE WHEN date BETWEEN '2015-01-09' AND '2015-01-16' AND service_type = 1
THEN units
END) WK2
FROM daily_sales as ds
group by ds.product_id
Every rail developer sooner or later hits his/her head against the walls of Active Record query interface just to find the solution in Arel.
Arel gives you the flexibility that you need in creating your query without using loops, etc. I am not going to give runnable code rather some hints how to do it yourself:
We are going to use arel_tables to create our query. For a model called for example Product, getting the Arel table is as easy as products = Product.arel_table
Getting sum of a column is like daily_sales.project(daily_sales[:units].count).where(daily_sales[:date].gt(BEGIN_DATE).where(daily_sales[:date].lt(END_DATE). You can chain as many wheres as you want and it will be translated into SQL ANDs.
Since we need to have multiple sums in our end result you need to make use of Common Table Expressions(CTE). Take a look at docs and this answer for more info on this.
You can use those CTEs from step 3 in combination with group and you are done!

SQL Server Update via Select Statement

I have the following sql statement and I want to update a field on the rows returned from the select statement. Is this possible with my select? The things I have tried are not giving me the desired results:
SELECT
Flows_Flows.FlowID,
Flows_Flows.Active,
Flows_Flows.BeatID,
Flows_Flows.FlowTitle,
Flows_Flows.FlowFileName,
Flows_Flows.FlowFilePath,
Flows_Users.UserName,
Flows_Users.DisplayName,
Flows_Users.ImageName,
Flows_Flows.Created,
SUM(CASE WHEN [Like] = 1 THEN 1 ELSE 0 END) AS Likes,
SUM(CASE WHEN [Dislike] = 1 THEN 1 ELSE 0 END) AS Dislikes
FROM Flows_Flows
INNER JOIN Flows_Users ON Flows_Users.UserID = Flows_Flows.UserID
LEFT JOIN Flows_Flows_Likes_Dislikes ON
Flows_Flows.FlowID=Flows_Flows_Likes_Dislikes.FlowID
WHERE Flows_Flows.Active = '1' AND Flows_Flows.Created < DATEADD(day, -60, GETDATE())
Group By Flows_Flows.FlowID, Flows_Flows.Active, Flows_Flows.BeatID,
Flows_Flows.FlowTitle, Flows_Flows.FlowFileName, Flows_Flows.FlowFilePath,
Flows_Users.UserName, Flows_Users.DisplayName, Flows_Users.ImageName,
Flows_Flows.Created
Having SUM(CASE WHEN [Like] = 1 THEN 1 ELSE 0 END) = '0' AND SUM(CASE WHEN [Dislike] = 1
THEN 1 ELSE 0 END) >= '0'
This select statement returns exactly what I need but I want to change the Active field from 1 to 0.
yes - the general structure might be like this: (note you don't declare your primary key)
UPDATE mytable
set myCol = 1
where myPrimaryKey in (
select myPrimaryKey from mytable where interesting bits happen here )
Because you haven't made your question more clear in what result you want to achieve, I'll provide an answer with my own assumptions.
Assumption
You have a select statement that gives you stuffs, and it works as desired. What you want it to do is to make it return results and update those selected rows on the fly - basically like saying "find X, tell me about X and make it Y".
Anwser
If my assumption is correct, unfortunately I don't think there is any way you can do that. A select does not alter the table, it can only fetch information. Similarly, an update does not provide more detail than the number of rows updated.
But don't give up yet, depending on the result you want to achieve, you have alternatives.
Alternatives
If you just want to update the rows that you have selected, you can
simply write an UPDATE statement to do that, and #Randy has provided
a good example of how it will be written.
If you want to reduce calls to server, meaning you want to make just
one call to the server and get result, as well as to update the
rows, you can write store procedures to do that.
Store procedures are like functions you wrote in programming languages. It essentially defines a set of sql operations and gives them a name. Each time you call that store procedure, the set of operations gets executed with supplied inputs, if any.
So if you want to learn more about store procedures you can take a look at:
http://www.mysqltutorial.org/introduction-to-sql-stored-procedures.aspx
If I understand correctly you are looking for a syntax to be able to select the value of Active to be 0 if it is 1. The syntax for something like that is
SELECT
Active= CASE WHEN Active=1 THEN 0 ELSE Active END
FROM
<Tables>
WHERE
<JOIN Conditions>