Get previous record column value in SQL - mysql

I have a table that has 3 columns: date,name,salary
I want to query the table and add in the result set another calculated column that can have 2 values: 'new' and 'same'.
The rule to assign the value is: order records by date ascending. if the name of the current record is different from the name of the previous record then the new column value will be 'start' else (if it is the same) it will be 'same'.
How can i do that? is there a function (something like prevRow())? Or do i have to make a "trick"?
How can i do this in mysql and DB2?

It would seem that DB2 (versions after 9.7 at least) support the LAG() window function, so this query should work (although I haven't been able to test it):
SELECT
date,
name,
salary
CASE
WHEN lag(name, 1) OVER (ORDER BY date ASC) = name THEN 'same'
ELSE 'start'
END AS calc_col
FROM your_table
ORDER BY date ASC

Depends on the database you are using, MS SQL has a lag function : http://msdn.microsoft.com/en-us/library/hh231256.aspx
There is a mysql hack for this, check out this question : Simulate lag function in MySQL
how to do lag operation in mysql

You can use some query like this
set #last_val = "";
select
if(#last_val = column,"same","start") as state,
#last_val := colum as temp
from table
;

Related

How do I find rows in a database that are not in the expected order?

Say I have a table with the structure
recordNumber: INTEGER (autoincrement)
insertedOn: DATETIME
Normally data gets inserted into the table it increments the recordNumber and insertedOn is always current time. Normally the following should be true
select insertedOn order by recordNumber === select insertedOn order by insertedOn
But that's actually not the case the question I have is how do I query the database so I can find the first recordNumber that would break the condition.
You can use LAG window function, but it depends on the particular database you are using.
If we assume that your increments are by '1', then this is a little more generic:
select top 1 *
from YrTbl Ths
where exists (select 1
from YrTbl Prev
where Prev.recordNumber+1=Ths.recordNumber
and Prev.insertedOn>=Ths.insertedOn
)
order by Ths.RecordNumber
TOP n might work a little differently in your environment; if you are using MySQL you might like to use LIMIT 1 at the end of the query, for example.

How to count when value crosses the average

I am trying to write a MySQL query that would count the number of times a value crosses a constant. The end result is we are tying to determine the relative 'noise' of the value via the amplitude and the frequency of the value. MIN() and MAX() provide the amplitude. Count() gives the number of samples that fit the criteria, but it doesn't provide how stable that value is. We are currently using MySQL 5.7 but we will be moving to MySQL 8.0 that provides the windowing features. Something like
Select Count(Value) over (order by logtime ROWS 1 Proeeding <123 AND 1 Following > 123) WHERE logtime BETWEEN...;
Thank your for any help you can provide.
SELECT Count(Value) WHERE Value > 123 AND logtime BETWEEN...;
SELECT Count(Value) WHERE Value < 123 AND logtime BETWEEN...;
Window functions are not available in MySQL versions before 8.0
With MySQL 5.7, we can emulate some window functions by using user-defined variables in a carefully crafted query. The MySQL Reference Manual gives explicit warning about using user-defined variables in a context like this. We are relying on behavior that is not guaranteed.
But as an example of the pattern I would use to achieve the specified result:
SELECT SUM(c.crossed_avg) AS count_crossed_avg
FROM (
SELECT IF( ( #prval > a.avg_ AND t.value < a.avg_ ) OR
( #prval < a.avg_ AND t.value > a.avg_ )
,1,0) AS crossed_avg
, #prval := t.value AS value_
FROM mytable t
CROSS
JOIN ( SELECT 123 AS avg_ ) a
CROSS
JOIN ( SELECT #prval := NULL ) i
WHERE ...
ORDER BY t.logtime
) c
To unpack this, focus first on the inline view query; that is, ignore the SELECT SUM() wrapper query, and run just the inline view query.
We order the rows by logtime so that we can process the rows in order.
We compare the value on the current row to the value from the previous row. If one is above average and the other is below average, then we return a 1, else we return 0.
Save the current value into the user-defined variable for comparing the next row. (Note: the order of operations is important; we are depending on MySQL to do that assignment after the evaluation of the IF() function.
The example query doesn't address the edge case when a row value is exactly equal to the average, e.g. a sequence of values 124.4 < 123.0 < 122.2. (We might want to consider changing the comparisons so that one includes the equality e.g. < and >=.

Do i use count(*) to count record or i add count column into my table directly

My team lead insisting me to add days entry count column within table and update it regularly. something like this
Get previous record
take count column value
Add .5 into that value
And update the count record in current record
like this
.5
1
1.5
2 //each time i have to get previous value to make new value which means select statment, then update statement
While I think that this is not the right way. I can count [using Count(*)] the record to display days which is easy why i bother to add it, use update command to know previous entry etc. The reason he told that we can get count directly without query bunch of records which is performance wise is fast. How you do this? what is correct way?
If I understand correctly, you just want row_number() divided by 2:
select t.*,
(row_number() over (order by ??) ) / 2.0
from t;
The ?? is for whatever column specifies the ordering of the table that you want.
UPDATE YourTable
SET COUNT_COLUMN = (SELECT MAX(COUNT_COLUMN) + 0.5
FROM YourTable
)
WHERE "Your condition for the current record";
For better performance add index on to COUNT_COLUMN column of YourTable.
Hi Fizan,
You can achieve this using function. You can create a function to get resultant value and update it in you column. Like this -
CREATE function Get_Value_ToBeUpdated
RETURN DECIMAL(10,2)
AS
BEGIN
DECLARE result decimal (10,2);
DECLARE previousValue decimal (10,2);
DECLARE totalCount int;
SELECT previousValue = SELECT MAX(columnName) FROM YourTable order by primaryColumn desc
SELECT totalCount = SELECT COUNT(1) FROM YourTable
SET result = ISNULL(previousValue,0) + ISNULL(totalCount,0)
RETURN result;
END
UPDATE YourTable SET COLUMNNAME = DBO.Get_Value_ToBeUpdated() WHERE Your condition
Thanks :)

sql error using between operator with date between two dates

i have an events table having start date and end date I am trying retrieve all the records by giving a date that is between start and end dates.
eg :
SELECT *
FROM `events`
WHERE '2017-01-29' BETWEEN start_date='2017-01-28'
AND end_date='2017-01-31'
but response is syntax error can any one help me to finish the query
Just list the columns.
WHERE '2017-01-29' BETWEEN start_date AND end_date
The values come from the table, you don't put them into the query.
According to mysql documentation (https://dev.mysql.com/doc/refman/5.7/en/comparison-operators.html#operator_between) the syntax for BETWEN is
expr BETWEEN min AND max
it is not
expr BETWEEN blabla=min AND stuff=max
Also, it is rather pointless to be using constants in all three expressions, because in this case the result will be known in advance (either always TRUE or always FALSE) without having to consult the values in your table.
It is kind of hard to give you an example without knowing the structure of your table, but what you probably want is something like
WHERE '2017-01-29' BETWEEN start_date
AND end_date
(assuming start_date and end_date are columns in your table)
or something like
WHERE some_column BETWEEN '2017-01-28'
AND '2017-01-31'
(assuming some_column is a column in your table.)
I believe you're trying to find all the rows where a date is 2017-01-29, and so, your query could be:
SELECT *
FROM `events`
WHERE
date = '2017-01-29';
If, however, you want all rows with date between 2017-01-28 and 2017-01-31, then you could do:
SELECT *
FROM `events`
WHERE
date BETWEEN '2017-01-28' AND '2017-01-31';
Instead of putting 2017-01-29 before WHERE, put the name of the field you want to filter by date, such as EventDate (or whatever your field is named).

DLAST in Access

I am using DLAST to return a specific field value for the last record. The issue I am having is that the last record isn't always the newest date record. I need to return the value of a specific field for the newest date record.
You can't depend on DLast() to return a value from the "last record" of a table unless you use a query based on the table and indicate how the rows should be ordered. From the Application.DLast Method help topic ...
NoteIf you want to return the first or last record in a set of records (a domain), you should create a query sorted as either
ascending or descending and set the TopValues property to 1.
If you want to use DLast(), create a query and use the query name as the domain argument. For example, with this as Query1 ...
SELECT ASSY
FROM L2_AOI1
ORDER BY [your date field];
... this should work as the text box's Control Source ...
=DLast("ASSY", "Query1")
However, you could use a different query which returns the most recent ASSY and use DLookup with that query. For example, with Query2 ...
SELECT TOP 1 ASSY
FROM L2_AOI1
ORDER BY [your date field] DESC;
=DLookup("ASSY", "Query2")
Either way, include an index on [your date field] to optimize performance.
You can also use DLookup directly with an SQL clause:
=DLookup("Assy", "L2_AOI1", "[YourDateField] = (Select Max([YourDateField]) From L2_AOI1)")