SQL date comparison in WHERE clause, TypoScript - sql

I want to compare dates in a TypoScript select.
Here's what I have (note that I commented the were clauses) :
lib.my_val = CONTENT
lib.my_val {
select {
pidInList = 100000
max = 1
#where = effective_date < CURDATE()
#where = TIMESTAMP(effective_date) < NOW()
orderBy = effective_date DESC
}
table = tx_my_table
renderObj = COA
renderObj {
5 = TEXT
5{
field = my_field
wrap = <span>|</span>
}
[...]
}
}
Which returns lines.
I tried to add a where statement any way I could with static dates or variables... without success. My understanding of the where clause is that everything after the = is dumped as is in the SQL query. But it seems I missed something.
Basically I want the TypoScript to generate a SQL Query smilar to this :
SELECT * FROM tx_my_table WHERE effective_date < NOW() ORDER BY effective_date DESC LIMIT 1;
This should be simple. Has anyone done this in the past?
Thanks!

Your TypoScript seems to be OK.
What happens if you enter the SQL Query directly into MySQL?
Note that with your code, only one record with pid=100000 is
selected.
Have you tried this:
--
lib.my_val {
select {
pidInList = 100000
max = 1
where = UNIX_TIMESTAMP(effective_date) < UNIX_TIMESTAMP()
orderBy = UNIX_TIMESTAMP(effective_date) DESC
}
table = tx_my_table
}
TYPO3 Wiki on select

Related

SnowFlake Query if an Id exists on each of the last 7 days

We INSERT new records every day to a table with say id and created_on column.
How do i identify if records with a particular identifier existed every day in the last 7 days ?
This can be done with a Stored Procedure:
CREATE OR REPLACE PROCEDURE TIME_TRAVEL(QUERY TEXT, DAYS FLOAT)
RETURNS VARIANT LANGUAGE JAVASCRIPT AS
$$
function run_query(query, offset) {
try {
var sqlText = query.replace('"at"', " AT(OFFSET => " + (offset + 0) + ") ");
return (snowflake.execute({sqlText: sqlText})).next();
}
catch(e) { return false }
}
var days, result = [];
for (days = 0; days < DAYS; days++)
if (run_query(QUERY, -days * 86400)) result.push(days);
return result;
$$;
CALL TIME_TRAVEL('SELECT * FROM TASK_HISTORY "at" WHERE QUERY_ID = ''019024ef-002e-8f71-0000-05e10030a782''', 7);
For the time travel query replace to work, put in an "at" as a table alias.
The return value is an array of day offsets when the query returns any value.
This will only work beyond DAYS=2 if you have Snowflake Enterprise Edition.
I did it with the below query
select id, sum(present) as total_count
from
(select id,feed_date, count(1) as present
from catalog_rca
where feed_date between '2019-11-19' and '2019-11-25'
group by 1,2) as temp
group by 1 having total_count = 7;

How to replace query conditions in a loop in Laravel?

I have a user table with name, status and distance. I want to get the users under a particular distance and if the result is empty I want to check it again with an incremented value.
$user = User::where('status',1);
$i = 10;
while($i < 50)
{
$user->having('distance', '<=', $i);
if($user->get()->count())
break;
$i = $i+5;
};
In the first loop I got the query correctly as SELECT * from users where status = 1 and having distance <= 10. If the result is empty in the second loop I got the query as SELECT * from users where status = 1 and having distance <= 10 and having distance <= 15. I want to get the query as SELECT * from users where status = 1 and having distance <= 15. What change should I do for this?
You are working here on objects and you should use clone:
$user = User::where('status',1);
$i = 10;
while($i < 50)
{
$query = (clone $user)->having('distance', '<=', $i);
if($query->get()->count())
break;
$i = $i+5;
}
In addition you are using:
$query->get()->count()
what causes that you get all records matching query from database and calculate their amount. If you just need to have their count, it's much better to use just:
$query->count()

How to group overlapping data in SQL

I have data in following fashion
Prog_Id Low_latency Max_Latency
a 1 4
a -1 5
a 3 8
a 11 12
a 12 15
Now I wish to see output as
Prog_Id Low_latency Max_Latency
a -1 8
a 11 15
Basically I wish to merge overlapping data. Can anyone help me with the code. I can manage time at the place of latency, if there is a solution with OVERLAPS clause.
Thanks
Rishabh
My initial answer was not always working. Now it looks like it is:
select distinct *
from (
select
t1.Prog_ID,
min(least(l, Low_latency)),
max(greatest(g, Max_Latency))
from yourtable t1 inner join (select
t1.Prog_ID,
least(t1.Low_latency, t2.Low_latency) l,
greatest(t1.Max_Latency, t2.Max_Latency) g
from
yourtable t1 inner join yourtable t2
on t1.Prog_ID=t2.Prog_ID
and t1.Low_latency<=t2.Max_Latency
and t1.Max_Latency>=t2.Low_Latency) t2
on t1.Prog_ID=t2.Prog_ID
and t1.Low_latency<=t2.g
and t1.Max_Latency>=t2.l
group by t1.Low_latency, t1.Max_latency) s
please see here. It's MySql code but can be converted for other DBMS.
It depends on which databse server (DBMS) you use. But there is no easy solution for. There could be a possibility to use Stored procedures . But I would prefer to do this in a programming language (which language do you use?)
After testing some around with querys of other people, I found no way in SQL.
Here is something simular to map reduce in java
public class YourData {
Double Low_latency;
Dobule Max_Latency;
int Prog_Id;
// add getter and setter here
public boolean tesetOverlapping(YourData data) {
if ((this.Low_latency<=data.Low_latency && data.Low_latency<=t1.Max_Latency) ¦¦ (this.Low_latency<=data.Max_Latency && data.Max_Latency<=this.Max_Latency)) {
this.Low_latency = Math.min(this.Low_latency, data.Low_latency);
this.Max_Latency = Math.min(this.Max_Latency, data.Max_Latency);
return true
}
return false;
}
}
String sql = "
SELECT
t1.Prog_Id,
t1.Low_latency,
t1.Max_Latency
FROM yourtable t1"
ArrayList<ArrayList<Double>> values = new ArrayList<ArrayList<Double>>();
while (row = get sql rows) {
int progIndex = values.indexOf(row.Prog_Id);
if (progIndex == -1) {
progIndex = values.indexOf(row.Prog_Id);
values.add(progIndex, new ArrayList<Double>());
}
values[progIndex].add(new YourData(row));
}
boolean foundOverlapping = false;
for (int progIndex = 0; progIndex < values.size(); progIndex++) {
// Do map reduce for each progIndex
do {
foundOverlapping = false;
for (int i = 0; i < values[progIndex].size(); i++) {
if (!values[progIndex].contains(i)) {
continue;
}
YourData cur = values[progIndex][i];
for (int x = 0; x < values[progIndex].size(); x++) {
if (i != x && values[progIndex].contains(x)) {
if (cur.tesetOverlapping(values[progIndex][x])) {
foundOverlapping = true;
values[progIndex].remove(x);
}
}
}
}
} while (foundOverlapping == true);
}
Assuming you want to group in a -infinity...9, 10...19, 20...29 pattern for the lower latency, you would need something like
SELECT
Prog_Id,
MIN(Low_latency) AS Low_latency,
MAX(Max_Latency) AS Max_Latency
FROM
your_table_name
GROUP BY
Prog_Id,
IF(FLOOR(Low_latency/10)<0,0,FLOOR(Low_latency/10))
Obviously the last line will depend on the RDBMS used, but should be quite similar among most.
You might also want to add an ORDER BY clause.

sql select with argument which can be NULL

What is the best way to have a select query which has an argument which can be NULL depending on some variable in the program?
I can think of two solutions (pseudocode):
bool valueIsNull;
int value;
query = "SELECT * FROM table WHERE field ";
if (valueIsNull)
{
query += "IS NULL";
}
else
{
query += "= ?";
}
statement st = sql.prepare(query);
if (!valueIsNull)
{
st.bind(0, value);
}
or
bool valueIsNull;
int value;
query = "SELECT * FROM table WHERE field = ? OR (? IS NULL AND field IS NULL)";
statement st = sql.prepare(query);
if (valueIsNull)
{
st.bindNull(0);
st.bindNull(1);
}
else
{
st.bind(0, value);
st.bind(1, value);
}
It is a lot of code for just a simple SELECT statement and I find it just ugly and unclear.
The cleanest way would be something like:
bool valueIsNull;
int value;
query = "SELECT * FROM table WHERE field = ?"; // <-- this does not work
statement st = sql.prepare(query);
st.bind(0, value, valueIsNull); // <-- this works
Obviously this does not work. But is there a clean way to handle this?
I do not think it matter much but I am using C++, cppdb and postgresql.
With Postgresql (but I believe not standard) you can use
SELECT * from some_table where field IS NOT DISTINCT FROM ?;
IS NOT DISTINCT FROM, unlike plain =, is true when both sides are NULL.
As you've noted, the main problem with this:
SELECT * FROM table WHERE field = ? OR (? IS NULL AND field IS NULL)
is that it is actually two parameters which need to be bound.
You can get around that with a (should be fairly portable) construct like:
SELECT *
FROM table
INNER JOIN (SELECT ? AS param1 /* FROM DUAL */) AS params
ON 1 = 1
WHERE field = param1
OR COALESCE(param1, field) IS NULL

Convert SQL - LINQ - Problem with using both Min/Max

Is there a online system which converts SQL - LINQ or can anyone else help convert the SQL - LINQ below?
SELECT MIN(startTime) As startTime, MAX(endTime) As endTime
FROM tblRA
LEFT JOIN tblA ON tblRA.asID = tblA.asID
WHERE 'xxxxxx' BETWEEN tblRA.startDate AND tblRA.endDate
AND tblA.availabilityDayOfWeek = 7
The main area I am having trouble is the .MAX/.MIN.
Heres what I have so far
public List<string> GetResourceAvailabilitiesByDate(DateTime searchDate)
{
DayOfWeek dayOfWeek = searchDate.DayOfWeek;
var minVal = from a in dc.tblResourceAvailabilities
join b in dc.tblAvailabilities on a.asID equals b.asID
where searchDate.Date >= a.startDate.Date && searchDate.Date <= a.endDate.Value.Date
&& b.availabilityDayOfWeek == (int)dayOfWeek
select b.startTime.ToShortTimeString();;
var maxVal = from a in dc.tblResourceAvailabilities
join b in dc.tblAvailabilities on a.asID equals b.asID
where searchDate.Date >= a.startDate.Date && searchDate.Date <= a.endDate.Value.Date
&& b.availabilityDayOfWeek == (int)dayOfWeek
select b.endTime.ToShortTimeString();
var min = minVal.Min(minVal.Min);
var max = maxVal.Max();
return min,max;
Thanks in advance for any help
Clare
I think your code is a little bit incorrect, and the first symptom of it is that you are using repeated code to define minval and maxval. I tried to simulate something similar to what you want and came to the following code, please adapt it to your needs.
public List<string> GetResourceAvailabilitiesByDate(DateTime searchDate)
{
DayOfWeek dayOfWeek = searchDate.DayOfWeek;
var vals = from a in dc.tblResourceAvailabilities
join b in dc.tblAvailabilities on a.asID equals b.asID
where searchDate.Date >= a.startDate.Date && searchDate.Date <= a.endDate.Value.Date
&& b.availabilityDayOfWeek == (int)dayOfWeek
select b;
var min = vals.Min(v => v.startTime).ToShortTimeString();
var max = vals.Max(v => v.startTime).ToShortTimeString();
return new List<string>() { min, max };
}
Some comments on your code, assuming it's C#.
You are trying to return an array of strings when you should be returning an array of dates.
Your where clause is pretty confuse. You're comparing the search date with startdate.Date and endDate.Value.Date. It does not make much sense.
Your select clause could select only b, or a, or whatever. You don't really need to select the date in it.