On 2018/08/26 2:16 PM, Csányi Pál wrote:

When the trigger is fired, those numbers are not updated in the
corresponding fields of the corresponding table.
To be more precise, the AllYearsMonthsDays trigger does not work.
The YearsRemainingMonthsDays trigger works.

What am I missing here?

--
Best, Pali

Many things are wrong with those triggers.
They can't use CTE's, the CASE statements evaluate equations, not values, so they have Boolean results, and one desperate space is missing after a union all statement, (to name the obvious ones) but then more hurtful to my OCD is the repetitive adding of CTEs, each of which evaluates 3 values of which, on every iteration, only 1 value is updated in the table - not to mention that the table is pressed into service as a VIEW, and the very expensive ON UPDATE trigger is filling in the table values that would be much more salient and simple with a VIEW.

Ok, enough about what is wrong with it. Here's how it can be fixed:

First, get rid of the triggers, completely.
Then get rid of the columns in the table named:  Years, RemainingMonths, and RemainingDays.

This will leave you with a Table scripted like this (I added Johnny to test future end-of-service dates):

CREATE TABLE "MyLengthOfService" (
  "id" INT PRIMARY KEY,
  "WorkPlaceName" TEXT,
  "StartDate" DATE,
  "EndDate" DATE,
  "WithWorkingTime" INT,
  "Comment" TEXT
);
INSERT INTO "MyLengthOfService" ("id","WorkPlaceName","StartDate","EndDate","WithWorkingTime","Comment") VALUES
 (1,'Name of the 1. work place','1983-07-11','1984-08-31',1,'workman')
,(2,'Name of the 2. work place','1984-11-01','1986-01-15',1,'workman')
,(3,'Name of the 3. work place','1986-01-16','1999-07-16',1,'workman')
,(4,'Name of the 4. work place','2000-02-01','2000-08-31',1,'teacher')
,(5,'Name of the 4. work place','2000-09-01','2001-01-31',0.5,'teacher')
,(6,'Name of the 4. work place','2001-02-01','2018-08-26',1,'teacher')
,(7,'Johnny','2018-05-01','2019-04-30',1,'workman')
;


Then, add this View:

CREATE VIEW MyLengthOfServiceTotal AS
WITH worktime(id, dStart, dEnd) AS (
  SELECT id, date(StartDate), date(EndDate) FROM MyLengthOfService
), timediff(id, years, months, days) AS (
  SELECT id,
      CAST(strftime('%Y',dEnd) AS INT)-CAST(strftime('%Y',dStart) AS INT),
      CAST(strftime('%m',dEnd) AS INT)-CAST(strftime('%m',dStart) AS INT),
      CAST(strftime('%d',dEnd) AS INT)-CAST(strftime('%d',dStart) AS INT)
    FROM worktime
), timefix(id, years, months, days) AS (
  SELECT id,
      CASE WHEN years  < 0 THEN 0 WHEN months < 0 THEN years-1 ELSE years END,
      CASE WHEN months < 0 THEN months+12 ELSE months END,
      CASE WHEN days   < 0 THEN days+30   ELSE days END
    FROM timediff
), post(id, years, months, days) AS (
  SELECT id,
      CASE WHEN days>29 AND months = 11 THEN years+1 ELSE years END,
      CASE WHEN days>29 THEN months+1 ELSE months END,
      CASE WHEN days>29 THEN 0 ELSE days+1 END
    FROM timefix
)
SELECT post.id, post.years AS TotalYears, post.months AS TotalMonths, post.days AS TotalDays
  FROM post

The workings is simple: it calculates the differences in years, months and days between the starting and ending dates in the timediff CTE. Then it corrects those for overflow in the timefix CTE, and then lastly the post CTE is a processing step for some rules that are specific to your case (like adding a day, calling 30+ days a month, etc.).

This will now allow you to query things like this:

SELECT A.*, B.TotalYears, B.TotalMonths, B.TotalDays
FROM MyLengthOfService AS A
  JOIN MyLengthOfServiceTotal AS B ON B.id = A.id
;
  --     |                           | |            | WithWor- |         | Total- | Total- | Total-   --  id | WorkPlaceName             | StartDate  | EndDate    | kingTime | Comment | Years  | Months |  Days   -- --- | ------------------------- | ---------- | ---------- | -------- | ------- | ------ | ------ | ------   --  1  | Name of the 1. work place | 1983-07-11 | 1984-08-31 |        1 | workman |    1   |    1   |   21   --  2  | Name of the 2. work place | 1984-11-01 | 1986-01-15 |        1 | workman |    1   |    2   |   15   --  3  | Name of the 3. work place | 1986-01-16 | 1999-07-16 |        1 | workman |   13   |    6   |    1   --  4  | Name of the 4. work place | 2000-02-01 | 2000-08-31 |        1 | teacher |    0   |    7   |    0   --  5  | Name of the 4. work place | 2000-09-01 | 2001-01-31 |      0.5 | teacher |    0   |    5   |    0   --  6  | Name of the 4. work place | 2001-02-01 | 2018-08-26 |        1 | teacher |   17   |    6   |   26   --  7  | Johnny                    | 2018-05-01 | 2019-04-30 |        1 | workman |    0   |   11   |   30

which will show you what you had already asked for - i.e. the length of service of all the people. You could also make this into a view so you only need to query 1 single item. (If that's a requirement)

Now, once that is done, here are two more views that will give you more information - if it is ever needed and if you plan ahead, i.e. adding service EndDate that are not yet reached. The first view below will show the Service time Elapsed (i.e. how long have they been in service until today). The next one will show the Service time remaining (i.e. how long do they still work until the end of their service - if their work did not end yet, else showing Zero). Then at the end, there is a last view which adds all this together into one single view that you can query with all information available and a sample query to call it.


CREATE VIEW MyLengthOfServiceElapsed AS
WITH worktime(id, dStart, dEnd) AS (
  SELECT id, date(StartDate), CASE WHEN date('now') < date(EndDate) THEN date('now') ELSE date(EndDate) END FROM MyLengthOfService
), timediff(id, years, months, days) AS (
  SELECT id,
      CAST(strftime('%Y',dEnd) AS INT)-CAST(strftime('%Y',dStart) AS INT),
      CAST(strftime('%m',dEnd) AS INT)-CAST(strftime('%m',dStart) AS INT),
      CAST(strftime('%d',dEnd) AS INT)-CAST(strftime('%d',dStart) AS INT)
    FROM worktime
), timefix(id, years, months, days) AS (
  SELECT id,
      CASE WHEN years  < 0 THEN 0 WHEN months < 0 THEN years-1 ELSE years END,
      CASE WHEN months < 0 THEN months+12 ELSE months END,
      CASE WHEN days   < 0 THEN days+30   ELSE days END
    FROM timediff
), post(id, years, months, days) AS (
  SELECT id,
      CASE WHEN days>29 AND months = 11 THEN years+1 ELSE years END,
      CASE WHEN days>29 THEN months+1 ELSE months END,
      CASE WHEN days>29 THEN 0 ELSE days+1 END
    FROM timefix
)
SELECT post.id, post.years AS ElapsedYears, post.months AS ElapsedMonths, post.days AS ElapsedDays
  FROM post
;


CREATE VIEW MyLengthOfServiceRemain AS
WITH worktime(id, dStart, dEnd) AS (
  SELECT id, CASE WHEN date('now') BETWEEN date(StartDate) AND date(EndDate) THEN date('now') ELSE date(EndDate) END, date(EndDate)
    FROM MyLengthOfService
), timediff(id, years, months, days) AS (
  SELECT id,
      CAST(strftime('%Y',dEnd) AS INT)-CAST(strftime('%Y',dStart) AS INT),
      CAST(strftime('%m',dEnd) AS INT)-CAST(strftime('%m',dStart) AS INT),
      CAST(strftime('%d',dEnd) AS INT)-CAST(strftime('%d',dStart) AS INT)
    FROM worktime
), timefix(id, years, months, days) AS (
  SELECT id,
      CASE WHEN years  < 0 THEN 0 WHEN months < 0 THEN years-1 ELSE years END,
      CASE WHEN months < 0 THEN months+12 ELSE months END,
      CASE WHEN days   < 0 THEN days+30   ELSE days END
    FROM timediff
), post(id, years, months, days) AS (
  SELECT id,
      CASE WHEN days>29 AND months = 11 THEN years+1 ELSE years END,
      CASE WHEN days>29 THEN months+1 ELSE months END,
      CASE WHEN days>29 THEN 0 ELSE days END
    FROM timefix
)
SELECT post.id, post.years AS RemainYears, post.months AS RemainMonths, post.days AS RemainDays
  FROM post
;


CREATE VIEW MyLengthOfServiceAll AS
SELECT A.*,
       B.TotalYears, B.TotalMonths, B.TotalDays,
       C.ElapsedYears, C.ElapsedMonths, C.ElapsedDays,
       D.RemainYears, D.RemainMonths, D.RemainDays
  FROM MyLengthOfService AS A
  JOIN MyLengthOfServiceTotal AS B ON B.id = A.id
  JOIN MyLengthOfServiceElapsed  AS C ON C.id = A.id
  JOIN MyLengthOfServiceRemain AS D ON D.id = A.id
;


This Query will then show all:

SELECT * FROM MyLengthOfServiceAll;


This is all working well on sqlite 3.24.0 on my side, but I may have copy-pasted something wrong - if you have any questions or difficulties, please ask again.

Hope that helps,
Ryan

_______________________________________________
sqlite-users mailing list
sqlite-users@mailinglists.sqlite.org
http://mailinglists.sqlite.org/cgi-bin/mailman/listinfo/sqlite-users

Reply via email to