Компилятору позволяют сделать одно неявное преобразование для разрешения параметров к функции. То, что это означает, - то, что компилятор может использовать конструкторов, вызываемых с единственный параметр для преобразования от одного типа до другого для получения правильного типа для параметра.
Вот класс в качестве примера с конструктором, который может использоваться для неявных преобразований:
class Foo
{
public:
// single parameter constructor, can be used as an implicit conversion
Foo (int foo) : m_foo (foo)
{
}
int GetFoo () { return m_foo; }
private:
int m_foo;
};
Вот простая функция, которая берет Foo
объект:
void DoBar (Foo foo)
{
int i = foo.GetFoo ();
}
и вот то, где эти DoBar
функция вызвана.
int main ()
{
DoBar (42);
}
аргумент не Foo
объект, а int
. Однако там существует конструктор для Foo
, который берет int
, таким образом, этот конструктор может использоваться для преобразования параметра в корректный тип.
компилятору позволяют сделать это однажды для каждого параметра.
Добавление префикса explicit
ключевое слово конструктору препятствует тому, чтобы компилятор использовал того конструктора для неявных преобразований. Добавление его к вышеупомянутому классу создаст ошибку компилятора при вызове функции DoBar (42)
. Теперь необходимо призвать к преобразованию явно с [1 111]
причина, которую Вы могли бы хотеть сделать, это должно избежать случайной конструкции, которая может скрыть ошибки. Изобретенный пример:
MyString(int size)
класс с конструктором, который создает строку данного размера. У Вас есть функция print(const MyString&)
, и Вы звоните print(3)
(когда Вы на самом деле намеревались звонить print("3")
). Вы ожидаете, что это распечатает "3", но это печатает пустую строку длины 3 вместо этого. Допустим, меня вдохновил Эндрю из NZSG. Я также сделал функцию с облицовкой трубы.
create or replace package testpl is
type outrec_type is record
( from_id ticket.id%type
, to_id ticket.id%type
, assigned_to ticket.assigned_to%type);
type outrec_table is table of outrec_type;
function pltest return outrec_table pipelined;
end;
/
create or replace package body testpl is
function pltest return outrec_table pipelined
is
l_outrec outrec_type;
l_first_time boolean := true;
begin
for r_tick in (select id, assigned_to from ticket order by id) loop
if (r_tick.assigned_to != l_outrec.assigned_to or l_first_time) then
if not l_first_time then
pipe row (l_outrec);
else
l_first_time := false;
end if;
l_outrec.assigned_to := r_tick.assigned_to;
l_outrec.from_id := r_tick.id;
end if;
l_outrec.to_id := r_tick.id;
end loop;
pipe row (l_outrec);
return;
end;
end;
/
Вы можете проверить это с помощью:
select * from table(testpl.pltest);
Это примерно в два раза быстрее, чем решение Роба ван Вейка в моей системе Windows XP Oracle 11.1.0.6.0.
Конструкция
for r_tick in (select ....) loop
....
end loop;
имеет очень приличную производительность в Oracle 10 и 11. В большинстве случаев решения только на SQL работают быстрее, но я думаю, что здесь PL / SQL быстрее.
Вам необходимо убедиться, что другие пользователи этого репозитория не загружают неправильные изменения или не пытаются строить на основе коммитов, которые вы хотите удалить, потому что вы собираетесь перемотать историю.
Затем вам нужно «принудительно» нажать старую ссылку.
git push -f origin last_known_good_commit:branch_name
или в вашем случае
git push -f origin cc4b63bebb6:alpha-0.3.0
Вы можете установить receive.denyNonFastForwards
в удаленном репозитории. В этом случае вы получите сообщение об ошибке, содержащее фразу [удаленный отказ]
.
В этом сценарии вам придется удалить и заново создать ветку.
git push origin :alpha-0.3.0
git push origin cc4b63bebb6:refs/heads/alpha-0.3.0
Если это не так. не работает - возможно, из-за того, что у вас установлен receive.denyDeletes
, тогда у вас должен быть прямой доступ к репозиторию. Затем в удаленном репозитории вам нужно выполнить что-то вроде следующей команды сантехники.
Роб.
Ладно, это некрасиво, но работает. И никто еще не сделал ничего более красивого, так что, возможно, это способ сделать это.
select min(from_id), to_id, assigned_to from
(
select from_id, max(to_id) as to_id, assigned_to from
(
select t1.id as from_id, t2.id as to_id, t1.assigned_to
from ticket t1
inner join ticket t2 on t1.assigned_to = t2.assigned_to and t2.id >= t1.id
where not exists
(
select * from ticket t3
where t3.ID > t1.ID
and t3.ID < t2.ID
and t3.assigned_to != t1.assigned_to
)
) x
group by from_id, assigned_to
) y
group by to_id, assigned_to
;
Я использую mysql; вполне может быть некоторая добродетель оракула, которая делает это лучше - как вполне может быть более элегантный простой sql. Но, по крайней мере, это начало.
это должно работать. Решение состоит из нескольких встроенных представлений, каждое из которых что-то вычисляет. Я прокомментировал то, что собирался сделать. Вы, конечно, должны читать комментарии изнутри, когда это выполняется.
--get results by grouping by interval_begin
SELECT MIN(id) from_id,
MAX(id) to_id,
MAX(assigned_to) assigned_to
FROM ( --copy ids of a first row of each interval of ids to the all following rows of that interval
SELECT id,
assigned_to,
MAX(change_at) over(ORDER BY id) interval_begin
FROM ( --find each id where a change of an assignee occurs and "mark" it. Dont forget the first row
SELECT id,
assigned_to,
CASE
WHEN (lag(assigned_to) over(ORDER BY id) <> assigned_to OR lag(assigned_to)
over(ORDER BY id) IS NULL) THEN
id
END change_at
FROM ticket))
GROUP BY interval_begin
ORDER BY from_id;
;
Я провел несколько тестов с Oracle express edition 10.2.0.1.0
Я использовал этот сценарий для заполнения билета таблицы 1179648 строками:
create table ticket (id,assigned_to)
as
select 100, 'raju' from dual union all
select 101, 'raju' from dual union all
select 102, 'raju' from dual union all
select 103, 'anil' from dual union all
select 104, 'anil' from dual union all
select 105, 'sam' from dual union all
select 106, 'raju' from dual union all
select 107, 'raju' from dual union all
select 108, 'anil' from dual
/
begin
for i in 1..17 loop
insert into ticket
select id + (select count(*) from ticket), assigned_to
from ticket;
end loop;
end;
/
commit;
SQL> select count(*) from ticket;
COUNT(*)
----------
1179648
Оператор select Роба ван Вейка занимает 1,6 секунды. средний, Оператор select от Mesays в среднем 2,8 секунды, оператор select Micheal Pravda - 4,2 секунды и Эндрю из заявления NZSG в среднем 9,6 секунды.
Таким образом, конвейерная функция в Oracle XE работает медленнее. А может кому-то нужно улучшить конвейерную функцию ...?
Вы можете наклониться назад, пытаясь достичь этого на чистом SQL, или вы можете создать что-то более длинное, но гораздо более легкое для понимания и более эффективное с точки зрения производительности - используйте конвейерную версию function
По сути, функция будет принимать указатель ref, который должен быть предварительно упорядочен по идентификатору, и затем передавать строки по конвейеру только тогда, когда непрерывный блок записей закончился.
CREATE TABLE assignment
(
a_id NUMBER,
assigned_to VARCHAR2(4000)
);
CREATE OR REPLACE package PCK_CONTIGUOUS_GROUPBY as
TYPE refcur_t IS REF CURSOR RETURN assignment%ROWTYPE;
TYPE outrec_typ IS RECORD (
from_id NUMBER,
to_id NUMBER,
assigned_to VARCHAR2(4000));
TYPE outrecset IS TABLE OF outrec_typ;
FUNCTION f_cont_groupby(p refcur_t)
RETURN outrecset PIPELINED;
end;
/
CREATE OR REPLACE package body pck_contiguous_groupby as
FUNCTION f_cont_groupby(p refcur_t) RETURN outrecset PIPELINED IS
out_rec outrec_typ;
in_rec p%ROWTYPE;
first_id assignment.a_id%type;
last_id assignment.a_id%type;
last_assigned_to assignment.assigned_to%type;
BEGIN
LOOP
FETCH p INTO in_rec;
EXIT WHEN p%NOTFOUND;
IF last_id IS NULL THEN
-- First record: don't pipe
first_id := in_rec.a_id;
ELSIF last_id = in_rec.a_id - 1 AND last_assigned_to = in_rec.assigned_to THEN
-- Contiguous block: don't pipe
NULL;
ELSE
-- Block not contiguous: pipe
out_rec.from_id := first_id;
out_rec.to_id := last_id;
out_rec.assigned_to := last_assigned_to;
PIPE ROW(out_rec);
first_id := in_rec.a_id;
END IF;
last_id := in_rec.a_id;
last_assigned_to := in_rec.assigned_to;
END LOOP;
CLOSE p;
-- Pipe remaining row
out_rec.from_id := first_id;
out_rec.to_id := last_id;
out_rec.assigned_to := last_assigned_to;
PIPE ROW(out_rec);
RETURN;
END;
END pck_contiguous_groupby;
/
а затем, чтобы попробовать это, заполнить таблицу и запустите:
SELECT * FROM TABLE(pck_contiguous_groupby.f_cont_groupby (CURSOR (SELECT a_id, assigned_to FROM assignment ORDER BY a_id)));
Я полагаю, вам нужна одна из аналитических функций Oracle . Вам повезло, если вы используете Oracle, потому что другие СУБД не имеют этой функции. Они позволяют писать SQL, который позволяет запрашивать данные относительно соседних строк, например, вычислять скользящие средние. У меня нет базы данных Oracle, с которой можно было бы поиграть, но я думаю, что это будет примерно так:
SELECT MIN(ID) AS From_Id, MAX(ID) AS To_Id, Assigned_To
FROM Ticket
PARTITION BY Assigned_To
ORDER BY From_Id
Вот мое предложение, не очень хорошо протестированное, но в моей голове оно звучит правильно, если id уникален и является непрерывной последовательностью. Посмотрите внизу на sql-запрос.
SQL> create table ticket (id number, assigned_to varchar2(30));
Table created.
SQL> insert into ticket values (100, 'raju');
1 row created.
SQL> insert into ticket values (101, 'raju');
1 row created.
SQL> insert into ticket values (102, 'raju');
1 row created.
SQL> insert into ticket values (103, 'anil');
1 row created.
SQL> insert into ticket values (104, 'anil');
1 row created.
SQL> insert into ticket values (105, 'sam');
1 row created.
SQL> insert into ticket values (106, 'raju');
1 row created.
SQL> insert into ticket values (107, 'raju');
1 row created.
SQL> insert into ticket values (108, 'anil');
1 row created.
SQL> select a.id from_id
2 ,lead(a.id -1, 1, a.id) over (order by a.id) to_id
3 ,a.assigned_to
4 from (
5 select
6 id, assigned_to
7 ,lag(assigned_to, 1) over (order by id) prev_assigned_to
8 from ticket
9 ) a
10 where a.assigned_to != nvl(a.prev_assigned_to, a.assigned_to||'unique')
11 order by id
12 ;
FROM_ID TO_ID ASSIGNED_TO
---------- ---------- ------------------------------
100 102 raju
103 104 anil
105 105 sam
106 107 raju
108 108 anil