I would like to do this query to include the null result in another calculated field.
SELECT ft.fecha_inicio,
ft.fecha_fin,
IF(ft.fecha_fin is NULL, now(), ft.fecha_fin) fin,
TIMEDIFF(fin,ft.fecha_inicio) total,
IF (ISNULL(ft.fecha_fin), 1, 0) as encurso
FROM fabricaciones_tiempos ft
WHERE ft.id_fabricacion = 138;
is this possible?
You cannot directly use a calculated column as part of another column calculation, but you can do it like this:
SELECT
fecha_inicio,
fecha_fin,
TIMEDIFF(fin,fecha_inicio) total,
encurso
FROM (
SELECT ft.fecha_inicio,
ft.fecha_fin,
IF(ft.fecha_fin is NULL, now(), ft.fecha_fin) fin,
IF (ISNULL(ft.fecha_fin), 1, 0) as encurso
FROM fabricaciones_tiempos ft
WHERE ft.id_fabricacion = 138
) as q;
You can't use the alias but you can either include the original formula in place or assign the value to a variable....
SELECT ft.fecha_inicio,
ft.fecha_fin,
IF(ft.fecha_fin is NULL, now(), ft.fecha_fin) fin,
TIMEDIFF(IF(ft.fecha_fin is NULL, now(), ft.fecha_fin),ft.fecha_inicio) total,
IF (ISNULL(ft.fecha_fin), 1, 0) as encurso
FROM fabricaciones_tiempos ft
WHERE ft.id_fabricacion = 138;
or....
SELECT ft.fecha_inicio,
ft.fecha_fin,
#fin:=IF(ft.fecha_fin is NULL, now(), ft.fecha_fin),
TIMEDIFF(#fin,ft.fecha_inicio) total,
IF (ISNULL(ft.fecha_fin), 1, 0) as encurso
FROM fabricaciones_tiempos ft
WHERE ft.id_fabricacion = 138;
Related
I've got the use case to version objects (identified by objectOwnerId and objectId group). I insert rows to ledger table with their respective hashes.
The order of the ledger table is identified by the compound PRIMARY KEY and its timestamp up to microsecond precision + additional 3 byte entropy at the end to prevent collisions (in case multiple rows gets inserted at the same microsecond).
Once data is stored I need efficient way to get the latest hash for multiple objects at once. I've came up with a query (please see end of this post) which is built from sub-selects with JOIN and GROUP BY, but it's pretty complex I think and I am looking for ways to address my problem in a simpler (if possible) way.
Is there any way for improvement?
It would've been simpler if I have PRIMARY KEY which isn't COMPOUND, in which case I could pass the max() value upwards, however that's not the case. I was also thinking if I could merge my TIMESTAMP(6) - 7 bytes with BINARY(3) - 3 bytes and store it as BINARY(10), but wasn't sure if that's easily possible.
Please find the schema, test data and SELECT queries below.
This is my table:
CREATE TABLE `ledger` (
`objectOwnerId` CHAR(10) NOT NULL,
`objectId` VARCHAR(50) NOT NULL,
`objectHash` BINARY(16) NOT NULL,
`timestamp` TIMESTAMP(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6),
`timestampAdditionalEntropy` BINARY(3) NOT NULL,
PRIMARY KEY (`timestamp`, `timestampAdditionalEntropy`),
UNIQUE(`objectHash`),
INDEX(`objectId`(10))
);
Let's insert some values:
INSERT INTO ledger (objectOwnerId, objectId, objectHash, timestampAdditionalEntropy) VALUES ('owneraaaaa', 'ida', unhex(substring(sha1(random_bytes(16)), 1, 32)), random_bytes(3));
INSERT INTO ledger (objectOwnerId, objectId, objectHash, timestampAdditionalEntropy) VALUES ('owneraaaaa', 'ida', unhex(substring(sha1(random_bytes(16)), 1, 32)), random_bytes(3));
INSERT INTO ledger (objectOwnerId, objectId, objectHash, timestampAdditionalEntropy) VALUES ('owneraaaab', 'idb', unhex(substring(sha1(random_bytes(16)), 1, 32)), random_bytes(3));
INSERT INTO ledger (objectOwnerId, objectId, objectHash, timestampAdditionalEntropy) VALUES ('owneraaaab', 'idb', unhex(substring(sha1(random_bytes(16)), 1, 32)), random_bytes(3));
INSERT INTO ledger (objectOwnerId, objectId, objectHash, timestampAdditionalEntropy) VALUES ('owneraaaab', 'idb', unhex(substring(sha1(random_bytes(16)), 1, 32)), random_bytes(3));
We've got this dataset:
# objectOwnerId, objectId, objectHash, timestamp, HEX(CAST(timestampAdditionalEntropy AS CHAR(6) CHARACTER SET utf8))
#'owneraaaab', 'idb', 'A8D3B63EFC6C63FD996B8D1931FBF748', '2019-05-29 11:38:12.353521', '725E3D'
#'owneraaaab', 'idb', '9B7395F9EE2F2363BA89C7FBAEDDBB54', '2019-05-29 11:38:12.352524', '8B8162'
#'owneraaaab', 'idb', '80393C5FF4492342D073B5F8B3388EC2', '2019-05-29 11:38:12.351569', 'FEAA02'
#'owneraaaaa', 'ida', '0D84F725ACAC87838C34742CA00BBEF7', '2019-05-29 11:38:12.350648', '41E425'
#'owneraaaaa', 'ida', '9A82C936A25C4648BFB75B692850841B', '2019-05-29 11:38:12.349625', '470685'
returned by this query:
select objectOwnerId, objectId, HEX(CAST(objectHash AS CHAR(32) CHARACTER SET utf8)) as objectHash, timestamp, HEX(CAST(timestampAdditionalEntropy AS CHAR(6) CHARACTER SET utf8))
from ledger
order by timestamp desc, timestampAdditionalEntropy desc;
I need to get this:
# objectOwnerId, objectId, objectHash, timestamp, HEX(CAST(s.timestampAdditionalEntropy AS CHAR(6) CHARACTER SET utf8))
#owneraaaaa, ida, 0D84F725ACAC87838C34742CA00BBEF7, 2019-05-29 11:38:12.350648, 41E425
#owneraaaab, idb, A8D3B63EFC6C63FD996B8D1931FBF748, 2019-05-29 11:38:12.353521, 725E3D
which this query can return:
select s.objectOwnerId, s.objectId, HEX(CAST(objectHash AS CHAR(32) CHARACTER SET utf8)) as objectHash, s.timestamp, HEX(CAST(s.timestampAdditionalEntropy AS CHAR(6) CHARACTER SET utf8)) from (
select s.objectOwnerId, s.objectId, s.timestamp, max(i.timestampAdditionalEntropy) as timestampAdditionalEntropy from (
select objectOwnerId, objectId, max(timestamp) as timestamp
from ledger where ((objectOwnerId = 'owneraaaaa' AND objectId = 'ida') OR (objectOwnerId = 'owneraaaab' AND objectId = 'idb'))
group by objectOwnerId, objectId
) s
JOIN ledger i on i.objectOwnerId = s.objectOwnerId and i.objectId = s.objectId and i.timestamp = s.timestamp
group by objectOwnerId, objectId, timestamp
) s
JOIN ledger i on i.objectOwnerId = s.objectOwnerId and i.objectId = s.objectId and i.timestamp = s.timestamp and i.timestampAdditionalEntropy = s.timestampAdditionalEntropy
How can I express the below statement as a SQL query ?
IF EXISTS (SELECT * FROM expense_history
WHERE user_id = 40
AND DATE_FORMAT(expense_history.created_date , '%Y-%m-%d') = '2018-06-02'
AND camp_id='80')
UPDATE expense_history
SET clicks = clicks + 1,
amount = amount + 1
WHERE user_id = 40
AND DATE_FORMAT(expense_history.created_date, '%Y-%m-%d') = '2018-06-02'
AND camp_id = '80'
ELSE
INSERT INTO expense_history (camp_id, created_date, amount, user_id)
VALUES ('80', '2018-06-02 12:12:12', '1', '40')
END IF;
I just want to do increment clicks and amount if is set by day, else I want to add new row.
This is very tricky in MySQL. You are storing a datetime but you want the date part to be unique.
Starting in MySQL 5.7.?, you can use computed columns for the unique constraint. Here is an example:
create table expense_history (
user_id int,
camp_id int,
amount int default 0,
clicks int default 1,
. . .
created_datetime datetime, -- note I changed the name
created_date date generated always as (date(created_datetime)),
unique (user_id, camp_id, created_datetime)
);
You can then do the work as:
INSERT INTO expense_history (camp_id, created_datetime, amount, user_id)
VALUES (80, '2018-06-02 12:12:12', 1, 40)
ON DUPLICATE KEY UPDATE
amount = COALESCE(amount + 1, 1),
clicks = COALESCE(clicks + 1, 1);
Earlier versions of MySQL don't support generated columns. Nor do they support functions on unique. But you can use a trick on a prefix index on a varchar to do what you want:
create table expense_history (
user_id int,
camp_id int,
amount int default 0,
clicks int default 1,
. . .
created_datetime varchar(19),
unique (created_datetime(10))
);
This has the same effect.
Another alternative is to store the date and the time in separate columns.
I presumed your database is mysql, because of DATE_FORMAT() function(and edited your question as to be).
So, by using such a mechanism below, you can do what you want,
provided that a COMPOSITE PRIMARY KEY for camp_id, amount, user_id columns :
SET #camp_id = 80,
#amount = 1,
#user_id = 40,
#created_date = sysdate();
INSERT INTO expense_history(camp_id,created_date,amount,user_id,clicks)
VALUES(#camp_id,#created_date,#amount,#user_id,ifnull(clicks,1))
ON DUPLICATE KEY UPDATE
amount = #amount + 1,
clicks = ifnull(clicks,0)+1;
SQL Fiddle Demo
I have sql query, where if the difference between 2 times is greater than 1440, then it will divide by 7, if not it will return the actual value. The problem is that I am repeating the code in the return value.
SELECT
'IF(TIMESTAMPDIFF(MINUTE, now(), end_at) > 1440, TIMESTAMPDIFF(MINUTE, now(), end_at)/ 7, TIMESTAMPDIFF(MINUTE, now(), end_at)) as minutesLeft'
FROM table
How can I replace the repeating code to look like this?
SELECT
'IF(TIMESTAMPDIFF(MINUTE, now(), end_at) > 1440, timestamp / 7, timestamp ) as minutesLeft'
FROM table
You can try using in-statement assignments:
set #diff = null;
SELECT #diff := TIMESTAMPDIFF(MINUTE, now(), end_at),
IF( #diff > 1440, #diff / 7, #diff) as minutesLeft
FROM table
Wrap the select in a sub-query if you just want one column returned.
i am trying to calculate the values for a new column impressions which is equal to the sum of ( sum_retweet and sum_reply ) multiply by the value in the column followers_count. so for the first row it would be : (2+1)*812 but on condition that the total sum of sum_retweet and sum_reply must be greater than zero. If the sum is equal to zero than impressions will = to just the followers_count.
account_id, date, user_screenname, sum_retweet, sum_reply, followers_count, Reach
'9', '2008-06-11', 'A', '2', '1', '812', '1624'
'9', '2008-06-12', 'B', '0', '1', '813', '813'
Here is my current code:
CREATE VIEW `tweet_sum` AS
select `tweets`.`account_id` AS `account_id`,
`tweets`.`user_screenname` AS `user_screenname`,
CAST(`tweets`.`datetime` as date) AS `period`,
MAX(`tweets`.`followers_count`) AS `followers_count`,
SUM(`tweets`.`is_reply`) AS `sum_reply`,
SUM(`tweets`.`is_retweet`) AS `sum_retweet`,
MAX(`tweets`.`followers_count`) * ((SUM(`tweets`.`is_reply`) > 0) + (SUM(`tweets`.`is_retweet`) > 0)) as reach
from `tweets`
group by cast(`tweets`.`datetime` as date), tweets.username;
HOw do i add the calculations for the impressions column in?
Use a case statement for this:
case when SUM(`tweets`.`is_reply`) + SUM(`tweets`.`is_retweet`) > 0
then (SUM(`tweets`.`is_reply`) + SUM(`tweets`.`is_retweet`))
* `tweets`.`followers_count`
else `tweets`.`followers_count` END as newColumn
This would do it in SQL, but this syntax may not work in mysql (dont know):
CASE WHEN (Sum_Retweet + Sum_Reply) > 0
THEN (Sum_Retweet + Sum_Reply) * followers_count
ELSE followers_count
END
Field names would need to be changed to your actual field names.
Good Morning!
I am trying to combine two queries to make a table. (Please see code below)
`CREATE TABLE Layer_Loss
(
dYear INT NOT NULL,
EventNum INT NOT NULL,
Loss INT NULL,
Rec_L1 BIGINT NULL,
Rec_L2 BIGINT NULL,
Rec_L3 BIGINT NULL,
Cap_CML_L1 BIGINT NULL,
Cap_CML_L2 BIGINT NULL,
Cap_CML_L3 BIGINT NULL,
)
INSERT INTO Layer_Loss (dYear,EventNum, Loss, Rec_L1, Rec_L2, Rec_L3, Capped_CML_L1, Capped_CML_L2, Capped_CML_L3)
WITH c AS (SELECT Row_number() OVER (ORDER BY dYear) AS rownum,*
FROM Layer_Loss_Capped2)
SELECT *
FROM
(
SELECT dYear, ROW_NUMBER() OVER (Partition by dYear Order by dYear) as Event_Number, Loss
, 'Recovery_L1'=CASE
WHEN Loss<10000000 THEN 0
WHEN Loss<30000000 THEN 20000000-(30000000-Loss)
ELSE 20000000
END
, 'Recovery_L2'=CASE
WHEN Loss<30000000 THEN 0
WHEN Loss<60000000 THEN 30000000-(60000000-Loss)
ELSE 30000000
END
, 'Recovery_L3'=CASE
WHEN Loss<60000000 THEN 0
WHEN Loss<100000000 THEN 40000000-(100000000-Loss)
ELSE 40000000
END
, (SELECT *, 'Capped_CML_L1'=CASE
WHEN d.CML_L1>40000000 THEN 4000000
ELSE d.CML_L1
END
, (SELECT *, 'Capped_CML_L2'=CASE
WHEN d.CML_L2>60000000 THEN 6000000
ELSE d.CML_L1
END
, (SELECT *, 'Capped_CML_L3'=CASE
WHEN d.CML_L1>80000000 THEN 8000000
ELSE d.CML_L1
END
FROM
(
SELECT a.dYear, a.EventNum, a.Loss, a.Rec_L1, SUM(b.Rec_L1) AS CML_L1, SUM(b.Rec_L2) AS CML_L2, SUM(b.Rec_L3) as CML_L3
FROM c a
LEFT JOIN c b ON a.dYear = b.dYear AND b.rownum <= a.rownum
GROUP BY a.dYear, a.rownum, a.EventNum, a.Rec_L1, a.Loss
) AS d
) AS e
FROM ['04_AIR_StdHU_DS_noSS_ByTerr$']
) AS a
DROP TABLE Layer_Loss`
I have it so that the query about 'Recovery_L1', 'Recovery_L2', and 'Recovery_L3' are about of table "Layer_Loss", which I've called "Rec_L1", "Rec_L2", and "Rec_L3". When I try to add the query that leads to "Capped_CML_L1", "Capped_CML_L2", and "Capped_CML_L3" I get the following error:
"Msg 156, Level 15, State 1, Line 14
Incorrect syntax near the keyword 'WITH'.
Msg 319, Level 15, State 1, Line 14
Incorrect syntax near the keyword 'with'. If this statement is a common table expression, an xmlnamespaces clause or a change tracking context clause, the previous statement must be terminated with a semicolon."
I have tried moving 'WITH' clause around but end up with the same result.
Also, this is not my end result. My next step would be to subtract the current row from the previous row from the columns "Capped_CML_L1", "Capped_CML_L2", and "Capped_CML_L3" into a column called "Inc_Rec_L1", "Inc_Rec_L2", and "Inc_Rec_L3". I was thinking about using a cursor, but I have never used one before, so if you have any suggestions on this, that would be great too!
Thank you for your help!
EDIT:
`CREATE TABLE Layer_Loss
(
dYear INT NOT NULL,
EventNum INT NOT NULL,
Loss INT NULL,
Rec_L1 BIGINT NULL,
Rec_L2 BIGINT NULL,
Rec_L3 BIGINT NULL,
Cap_CML_L1 BIGINT NULL,
Cap_CML_L2 BIGINT NULL,
Cap_CML_L3 BIGINT NULL,
)
;WITH c AS (SELECT Row_number() OVER (ORDER BY dYear) AS rownum,*
FROM Layer_Loss_Capped2)
INSERT INTO Layer_Loss (dYear,EventNum, Loss, Rec_L1, Rec_L2, Rec_L3, Capped_CML_L1, Capped_CML_L2, Capped_CML_L3)
SELECT *
FROM
(
SELECT dYear, ROW_NUMBER() OVER (Partition by dYear Order by dYear) as Event_Number, Loss
, 'Recovery_L1'=CASE
WHEN Loss<10000000 THEN 0
WHEN Loss<30000000 THEN 20000000-(30000000-Loss)
ELSE 20000000
END
, 'Recovery_L2'=CASE
WHEN Loss<30000000 THEN 0
WHEN Loss<60000000 THEN 30000000-(60000000-Loss)
ELSE 30000000
END
, 'Recovery_L3'=CASE
WHEN Loss<60000000 THEN 0
WHEN Loss<100000000 THEN 40000000-(100000000-Loss)
ELSE 40000000
END
, (SELECT *, 'Capped_CML_L1'=CASE
WHEN d.CML_L1>40000000 THEN 4000000
ELSE d.CML_L1
END
, (SELECT *, 'Capped_CML_L2'=CASE
WHEN d.CML_L2>60000000 THEN 6000000
ELSE d.CML_L1
END
, (SELECT *, 'Capped_CML_L3'=CASE
WHEN d.CML_L1>80000000 THEN 8000000
ELSE d.CML_L1
END
FROM
(
SELECT a.dYear, a.EventNum, a.Loss, a.Rec_L1, SUM(b.Rec_L1) AS CML_L1, SUM(b.Rec_L2) AS CML_L2, SUM(b.Rec_L3) as CML_L3
FROM c a
LEFT JOIN c b ON a.dYear = b.dYear AND b.rownum <= a.rownum
GROUP BY a.dYear, a.rownum, a.EventNum, a.Rec_L1, a.Loss
) AS d
FROM ['04_AIR_StdHU_DS_noSS_ByTerr$']
) AS e
) AS f
) AS g
) AS a
DROP TABLE Layer_Loss`
When I put in the above edited code I get error:
Msg 156, Level 15, State 1, Line 58
Incorrect syntax near the keyword 'FROM'.
I would like to be able to reference Capped_CML_L1, Capped_CML_L2, and Capped_CML_L3 in another query or table or cursor later on. I wanted it to be under just 'e' but I'm not sure how with the parentheses
WITH must be separated from any preceding command by a ;.
When a CTE is used in a statement that is part of a batch, the statement before it must be followed by a semicolon.
Also, it must be the first part of the entire statement it's a part of, whether that be a plain SELECT or an INSERT. Try:
/* CREATE TABLE */
;WITH c AS (SELECT Row_number() OVER (ORDER BY dYear) AS rownum,*
FROM Layer_Loss_Capped2)
INSERT INTO Layer_Loss (dYear,EventNum, Loss, Rec_L1, Rec_L2, Rec_L3,
Capped_CML_L1, Capped_CML_L2, Capped_CML_L3)
SELECT *
FROM
(
SELECT dYear, ROW_NUMBER() OVER ...
(Have also moved the WITH before the INSERT, having realised what was being attempted)
See also Transact SQL Syntax conventions:
; Transact-SQL statement terminator.Although the semicolon is not required for most statements in this version of SQL Server, it will be required in a future version.
One of the main reasons for this is that there is a pre-existing use for the keyword WITH that modifies SELECT statements. By insisting on the ;, it makes the parse a lot easier.