Материал: Using_MySql,_MS_SQL_Server_and_Oracle

Внимание! Если размещение файла нарушает Ваши авторские права, то обязательно сообщите нам
-- номер дня недели (4)
-- номер полной недели месяца (3) -- номер в году недели, -- к которой относится -- анализируемая дата (42)
-- номер в году недели, к которой -- относится первый день месяца, -- к которому относится -- анализируемая дата (39)
-- номер дня в году (294)
-- номер в году первого дня месяца, к -- которому относится анализируемая
-- дата (275)

Пример 51: вычисление дат

Проверить работоспособность полученной функции можно выполнением следующего кода:

MySQL

1

2

3

4

Решение 7.4.1.b (проверка работоспособности) і

SELECT rsb_ldv, 'sb_start',

GetWeekAndDay('sb_s tart') AS 'DW' FROM 'subscriptions'

Код функции для MS SQL Server выглядит следующим образом:

MS SQL Решение 7.4.1

1CREATE.b FUNCTION GetWeekAndDay @date var DATETIME)

2RETURNS VARCHAR(4)

3AS

4BEGIN

5 DECLARE @day number TINYINT;

6 DECLARE @week number TINYINT;

7 DECLARE @current wn TINYINT;

8

9

10 DECLARE @first_dom_wn TINYINT;

11

12

13

14 DECLARE @current doy INT;

15 DECLARE @first_dom_doy INT;

16

17

18DECLARE @real iso week of month start TINYINT;

19-- ISO-номер в году недели, к которой относится первое число месяца,

20-- к которому относится анализируемая дата (39), для первых чисел

21-- января будет 0, а не 52 или 53, как это вычисляет MS SQL Server

22DECLARE @real iso week of this date TINYINT;

23-- ISO-номер в году недели, к которой относится анализируемая дата (42),

24-- для первых чисел января будет 0, а не 52 или 53, как это

25-- вычисляет MS SQL Server

26

27SET @day number = DATEPART dw DATEADD(day, -1, @date var );

28— @day number = DATEPART(dw, (2016.10.20 - 1)) =

29

--

DATEPART(dw, 2016.10.19) = 4

30

 

 

31SET @current wn = DATEPART(iso week, @date var); -- 42

32SET @first dom wn = DATEPART(iso week,

33

 

CONVERT(VARCHAR(6), @date var, 112) + '01');

34

— @first dom wn = DATEPART(iso week, '201610' + '01') =

35

--

DATEPART(iso week, '20161001') = 39

36

 

 

37SET @current doy = DATEPART dy @date var ; -- 294

38SET @first dom doy = DATEPART(dy,

39

CONVERT(VARCHAR(6|, @date var, 112 + '01');

40

-- @first dom doy = DATEPART(dy, '201610' + '01') =

41

DATEPART(dy, '20161001') = 275

42

 

43-- Актуально, например, для 2017.01.01

44IF @first dom wn > @first dom doy

45SET @real iso week of month start = 0

46ELSE SET @real iso week of month start = @first dom wn;

47

48-- Актуально, например, для 2017.01.02

49IF @current wn > @current doy

50SET @real iso week of this date = 0

51ELSE SET @real iso week of this date = @current wn;

Работа с MySQL, MS SQL Server и Oracle в примерах © EPAM Systems, RD Dep, 2016-2018 Стр: 565/545

Пример 51: вычисление дат

MS SQL I

Решение 7.4.1.b (продолжение)

|

52

SET @week number = @real iso week of this date -

53

@real_iso_week_of_month_start --(3)

54

 

 

55

IF (DATEPART dw, DATEADD(day,

1,

56

CONVERT(VARCHAR(6), @date var, 112)+ '01'))

57<= @day number

58SET @week_number = @week_number + 1;

60RETURN CONCAT('W', @week number, 'D', @day number ; -- W3D4

61END;

Проверить работоспособность полученной функции можно выполнением следующего кода:

MS SQL і Решение 7.4.1.b (проверка работоспособности) і

1SELECT [зЬЧаТ,

2[sb_start] ,

dbo GetWeekAndDayi[sb_start]) AS [DW] 4 FROM [subscriptions];

Код функции для Oracle выглядит следующим образом:

Oracle і Решение 7.4.1.b [

 

 

 

 

1

CREATE . OR ..... REPLACE . FUNCTION

GetWeekAndDaylSO(date_var ...... IN........................DATE)

2

RETURN

VARCHAR

 

 

 

3

IS

 

 

 

 

4

day_number NUMBER 1';

 

--

номер дня недели (4)

5

week_number NUMBER(1);

-- номер полной недели месяца (3)

6

current_wn NUMBER 3';

 

--

номер в году недели,

7

 

 

 

-- к которой относится

8

 

 

 

-- анализируемая дата (42)

9

first_dom_wn NUMBER'3

;

--

номер в году недели, к которой относится

10

 

 

 

-- первый день месяца, к которому относится

11

 

 

 

-- анализируемая дата (39)

12

current_doy NUMBER 5

;

--

номер дня в году (294)

13

first_dom_doy NUMBER(5);

-- номер в году первого дня месяца, к

14

 

 

 

-- которому относится анализируемая дата (275)

15

 

 

 

 

 

16real_iso_week_of_month_start NUMBER(3);

17-- ISO-номер в году недели, к которой относится первое число месяца,

18

--

к которому относится

анализируемая дата

(39), для первых чисел

19

--

января будет 0, а не

52 или 53, как это

вычисляет Oracle

20

 

 

 

 

21real_iso_week_of_this_date NUMBER 3 ;

22-- ISO-номер в году недели, к которой относится анализируемаядата (42),

23-- для первых чисел января будет 0, а не 52 или 53, как это

24-- вычисляет Oracle

25BEGIN

26day_number := date_var - NEXT_DAY date_var - 8, 'MON') + 1;

27-- day_number := 2016.10.20 - NEXT_DAY(2016.10.20 - 8, 'MON') + 1 =

28

--

2016.10.20

-

NEXT_DAY(2016.10.12, 'MON') + 1

29

--

2016.10.20

-

2016.10.17 + 1 = 4

30

 

 

 

 

 

31

current_wn := TO_NUMBER(TO_CHAR(date_var 'IW'));

42

32

first_dom_wn := TO_NUMBER(TO_CHAR(TRUNC(date_var

'mm'), 'IW')); 39

33— first_dom_wn := TO_NUMBER(TO_CHAR(TRUNC(2016.10.20, 'mm'), 'IW')) =

34— TO_NUMBER(TO_CHAR(2016.10.01, 'IW')) = 39

35

36current_doy := TO_NUMBER(TO_CHAR(date_var, 'DDD')); 294

37first_dom_doy := TO_NUMBER(TO_CHAR(TRUNC date_var, 'mm'), 'DDD'));

38

first_dom_doy := TO_NUMBER(TO_CHAR(TRUNC(2016.10.20, 'mm'), 'DDD')) =

39

TO NUMBER(TO CHAR(2016.10.01, 'DDD')) = 275

Работа с MySQL, MS SQL Server и Oracle в примерах © EPAM Systems, RD Dep, 2016-2018 Стр: 566/545

Пример 51: вычисление дат

Oracl

і

Решение 7.4.1.b

I

e

 

 

 

40

-- Актуально, например, для 2017.01.01

41

IF

first dom wn > first dom doy

42

 

THEN real iso week of month start := 0;

43

 

ELSE real iso week of month start := first dom wn;

44

END IF;

 

45

 

 

 

46

-- Актуально, например, для 2017.01.02

47

IF

current wn > current doy

48

 

THEN real iso week of this date := 0

49

 

ELSE real iso week of this date := current wn;

50

END IF;

 

51

 

 

 

52week number := real iso week of this date - real iso week of month start

53-- (3)

54

 

55

IF (TRUNC(date var 'mm') - NEXT DAY(TRUNC date var, 'mm') - 7, 'MON')

56

<= day number)

57THEN week number := week number + 1;

58END IF;

59

60RETURN 'W' || week number || 'D' || day number;

61END;

Проверить работоспособность полученной функции можно выполнением следующего кода:

 

Oracle

Решение 7.4.1.b (проверка работоспособности)

 

 

1

SELECT "sb_id"

 

2

 

"sb_start", GetWeekAndDay("sb_start") AS

4

FROM "subscriptions";

"DW"

На этом решение данной задачи завершено.

Задание 7.4.1.TSK.A: переписать решение{528} задачи 7.4.1.a{528} таким образом, чтобы запрос возвращал номер недели и номер дня недели в виде одной строки (например, W5D1) — аналогично тому, как результат возвращает функция, полученная в решении{532} задачи 7.4.1.b{528}.

Задание 7.4.1.TSK.B: переписать решение{528} задачи 7.4.1.a{528} для MS SQL Server и Oracle без использования общего табличного выражения.

Работа с MySQL, MS SQL Server и Oracle в примерах © EPAM Systems, RD Dep, 2016-2018 Стр: 567/545

Пример 52: получение комбинации неповторяющихся идентификаторов

7.4.2.Пример 52: получение комбинации неповторяющихся идентификаторов

Задача 7.4.2.a{536}: написать запрос, формирующий пару гарантированно неповторяющихся идентификаторов читателей.

О Задача 7.4.2.b{538}: оформить решение задачи 7.4.2.а{536} с использованием общих табличных выражений.

Ожидаемый результат 7.4.2.a.

После выполнения запроса должна быть сформирована пара идентификаторов читателей, значения которых гарантированно не должны дублироваться (при условии, что в таблице subscribers есть хотя бы две записи), например:

id_first id_second

3 1

Ожидаемый результат 7.4.2.b.

Поскольку само решение и является ожидаемым результатом, см. решение

7.4.2.b{538}.

ч Р Решение 7.4.2.a{536}.

Предположим, что у нас нет никакой информации об идентификаторах читателей (минимальное значение, максимальное значение, общее количество, непрерывность последовательности и т.д.), кроме того факта, что в таблице subscribers есть как минимум две записи (в противном случае задача не имеет решения).

Логику решения построим на том, что декартово произведение двух множеств, в одном из которых есть хотя бы два уникальных значения, гарантированно будет содержать пару уникальных значений.

Поясним эту идею на примере. Допустим, что мы случайных образом выбрали два набора идентификаторов читателей, причём нам «не повезло», и в обоих наборах есть одно и то же значение.

Набор 1

Набор 2

5

5

3

 

Декартово проиведение таких наборов даст следующий результат:

Значения из набора 1

Значения из набора 2

5

5

3

5

Легко заметить, что вторая комбинация содержит неповторяющиеся значения (что и необходимо по условию задачи). Очевидно, что если все три значения идентификаторов в исходных наборах будут различными, то в результирующем декартовом произведении также будет хотя бы одна (на самом деле - две) комбинации с неповторяющимися значениями.

Работа с MySQL, MS SQL Server и Oracle в примерах ©Богдан Марчук Стр: 568/545

Пример 52: получение комбинации неповторяющихся идентификаторов

Эта логика может быть нарушена в том и только в том случае, если в первом наборе оба значения идентификаторов совпадут, но мы можем не опасаться этого варианта развития событий, т.к. будем строить этот набор на основе значений первичного ключа, которые являются уникальными по определению.

Итак, решение данной задачи для MySQL выглядит следующим образом.

MySQL і Решение 7.4.2.a

1SELECT 'id first'

2'id second'

3

FROM (SELECT 's id' AS 'id first'

4

FROM

'subscribers'

5

ORDER BY RAND()

6

LIMIT

2) AS 'set1'

7CROSS JOIN

8(SELECT 's id' AS 'id second'

9FROM 'subscribers'

10ORDER BY RAND()

11LIMIT 1) AS 'set2'

12WHERE 'id first' != 'id second'

13LIMIT 1

Встроках 3-6 мы получаем пару значений для первого набора, в строках 811 получаем одно значение для второго набора, а оператор CROSS JOIN в строке 7

обеспечивает нам получение декартового произведения наборов. Условие в строке 12 гарантирует выполнение условия задачи (значения идентификаторов не должны совпадать).

Решение для MS SQL Server отличается лишь способом указания колчества возвращаемых строк (TOP вместо LIMIT) и способом упорядочивания по случайному числу (т.к. в MS SQL Server функция RAND будет возвращать одно и то же число для всех вызовов в рамках одного запроса).

MS SQL I Решение 7.4.2.a

|

1

SELECT TOP 1 [id first]

2

 

[id second]

3

FROM

(SELECT TOP 2 [s id] AS [id first]

4

 

FROM

[subscribers]

5

 

ORDER BY NEWID()) AS [set1]

6

 

CROSS JOIN

7

 

(SELECT TOP 1 [s id] AS [id second]

8

 

FROM

[subscribers]

9

 

ORDER BY NEWID()) AS [set2]

10

WHERE

[id_first] != [id_second]

Решение для Oracle также отличается лишь способом указания количества возвращаемых строк и (подзапрос с ROW_NUMBER) и способом упорядочивания по случайному числу (DBMS_RANDOM.RANDOM).

Решенеие получается таким «синтаксически перегруженным» потому, что Oracle начинает поддерживать синтаксис OFFSET ... FETCH только с 12-й версии, а мы работаем с 11-й.

Работа с MySQL, MS SQL Server и Oracle в примерах ©Богдан Марчук Стр: 569/545

Источник: https://studfile.net/preview/16420333/