Рекомендации по использованию SQL-запросов для нахождения отношений внешнего ключа

В статье рассматривается написание SQL-запросов для нахождения отношений внешнего ключа в базе данных IBM® DB2® for Linux®, UNIX®, and Windows®. На примере таблицы с первичным ключом вы узнаете, как возвратить дочерние таблицы и таблицы-потомки, а также маршруты отношения ссылочной целостности (RI) между родительской таблицей и этими дочерними элементами и потомками. Кроме того, вы увидите, каким образом можно изменить запрос с целью возвращения результатов для всех таблиц в базе данных.

Петрус Чан, инженер-консультант по программному обеспечению, IBM

Author photo for Petrus ChanПетрус Чан (Petrus Chan) более 15 лет занимается компилятором SQL Compiler продукта IBM DB2 for Linux, UNIX, and Window. П. Чан специализируется на функциях DB2 для активной работы с данными, таких как ограничения, триггеры и таблицы материализированных запросов. Ему принадлежит четыре патента на системы данных и на методики.



10.07.2013

Введение

Наличие в базе данных большого количества ограничений внешнего ключа может затруднить визуализацию отношений внешнего ключа между таблицами. В статье рассматривается написание SQL-запросов для нахождения отношений внешнего ключа в базе данных DB2 for Linux, UNIX, and Windows.

В частности, рассматриваются следующие варианты.

  • Для родительской таблицы заданного внешнего ключа возвращение RI-потомков и дочерних элементов, а также маршрутов RI-отношения между родительской таблицей и этими дочерними элементами и потомками.
  • Изменение предоставленного запроса с целью возвращения результатов для всех таблиц в базе данных.

Учебная схема

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

Листинг 1. Учебная схема
set schema newton;
                
create table grandparent (i1 int not null primary key, i2 int, i3 int);
create table parent (i1 int not null primary key, i2 int);
create table parent2 (i1 int  not null primary key, i2 int);
create table child  (i1 int not null primary key, i2 int, i3 int);
create table grandchild  (i1 int not null primary key, i2 int, i3 int);
                
alter table parent add constraint fkp1 foreign key (i2) references grandparent;
alter table parent2 add constraint fkp2 foreign key (i2) references grandparent;
alter table child add constraint fk1 foreign key (i2) references parent;
alter table child add constraint fk2 foreign key (i3) references parent2;
alter table grandchild add constraint fk3 foreign key (i2) references child;
alter table grandchild add constraint fk4 foreign key (i3) references parent2;
                
create table gp (i1 int not null, i2 int not null, i3 int, primary key (i1, i2));
create table p1 (i1 int not null primary key, i2 int, i3 int);
create table c11 (i1 int not null primary key, i2 int);
create table c12 (i1 int not null primary key, i2 int);
                
alter table p1 add constraint fkp1 foreign key (i2, i3) references gp;
alter table c11 add constraint fkc11 foreign key (i2) references p1;
alter table c12 add constraint fkc12 foreign key (i2) references p1;
alter table gp add constraint fkgp1 foreign key (i2) references c12;
                
create table self (i1 int not null primary key, i2 int);
alter table self add constraint fk_self foreign key (i2) references self;

Как отобразить все RI-ограничения

В самой простой форме список всех ограничений внешнего ключа можно получить посредством запроса к представлению каталога SYSCAT.REFERENCES.

SELECT * FROM SYSCAT.REFERENCES

Полученные результаты можно объединить с представлением SYSCAT.KEYCOLUSE с целью нахождения столбцов внешнего ключа.

Для создания — в виде разделенных запятыми значений – списка столбцов внешнего ключа, используемых в ограничениях ссылочной целостности, можно использовать агрегатную функцию LISTAGG () в процессе объединения SYSCAT.REFERENCES с SYSCAT.KEYCOLUSE (см. Листинг 2).

Листинг 2. Агрегатная функция LISTAGG ()
select  substr(R.reftabschema,1,12) as P_Schema, substr(R.reftabname,1,12) as PARENT,
        substr(R.tabschema,1,12) as C_Schema, substr (R.tabname,1,12) as CHILD,
        substr(R.constname,1,12) as CONSTNAME, 
        substr(LISTAGG(C.colname,', ') WITHIN GROUP (ORDER BY C.colname),1,20) as FKCOLS 
from syscat.references R, syscat.keycoluse C 
where R.constname = C.constname and R.tabschema = C.tabschema and R.tabname = C.tabname
group by R.reftabschema, R.reftabname, R.tabschema, R.tabname, R.constname;

Результаты работы функции показаны в Листинге 3.

Листинг 3. Выходная информация агрегатной функции LISTAGG ()
P_SCHEMA     PARENT       C_SCHEMA     CHILD        CONSTNAME    FKCOLS              
------------ ------------ ------------ ------------ ------------ ----------------
NEWTON       PARENT       NEWTON       CHILD        FK1          I2                  
NEWTON       PARENT2      NEWTON       CHILD        FK2          I3                  
NEWTON       CHILD        NEWTON       GRANDCHILD   FK3          I2                  
NEWTON       PARENT2      NEWTON       GRANDCHILD   FK4          I3                  
NEWTON       P1           NEWTON       C11          FKC11        I2                  
NEWTON       P1           NEWTON       C12          FKC12        I2                  
NEWTON       C12          NEWTON       GP           FKGP1        I2                  
NEWTON       GP           NEWTON       P1           FKP1         I2  , I3           
NEWTON       GRANDPARENT  NEWTON       PARENT       FKP1         I2                  
NEWTON       GRANDPARENT  NEWTON       PARENT2      FKP2         I2                  
NEWTON       SELF         NEWTON       SELF         FK_SELF      I2

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


Отображение всех дочерних элементов внешнего ключа и потомков данной таблицы

Для прослеживания отношений ссылочной целостности можно написать соответствующий рекурсивный запрос. Однако при использовании продукта DB2 for Linux, UNIX, and Windows версии 9.7 или выше более предпочтительным вариантом для рекурсивного прослеживания RI-отношений в SYSCAT.REFERENCES является иерархический запрос. Обратитесь к разделу Ресурсы для получения ссылок на дополнительную информацию.

Для использования иерархических запросов в DB2 требуется настройка параметра DB2_COMPATIBILITY_VECTOR:

db2set DB2_COMPATIBILITY_VECTOR=08
db2stop
db2start

Иерархические запросы позволяют специфицировать конструкции START WITH и CONNECT BY.

Например, запрос Query 1, показанный в Листинге 4, возвращает всех RI-потомков ссылочной целостности, а также уникальный маршрут к ним от корневой таблицы NEWTON.GRANDPARENT.

Листинг 4. Запрос Query 1
with 
root_parents (root_parent_schema, root_parent_name) AS
 (select * from table(values ('NEWTON', 'GRANDPARENT')))
select 
 substr(connect_by_root reftabname,1,11) as root,
 substr (level, 1,5) as lvl,
--  substr(reftabschema,1,6) as parent_schema,
 substr(reftabname,1,11) as parent, 
--  substr(tabschema,1,6) as child_schema,
 substr(tabname,1,10) as child, 
 substr(constname,1,5) as cnst, 
 substr(sys_connect_by_path(reftabname, '->') || '->' || 
 substr(tabname,1,20),1,42) as chain
from syscat.references
start with (reftabschema,reftabname) in (select root_parent_schema, 
                                        root_parent_name from root_parents)
connect by nocycle prior  tabname = reftabname 
                      and tabschema = reftabschema;

Примечание: Имя схемы было удалено из выходной информации всех запросов с целью улучшения форматирования.

Запрос Query 1 возвращает результаты, показанные в Листинге 5.

Листинг 5. Выходная информация запроса Query 1
ROOT        LVL   PARENT      CHILD      CNST  CHAIN                                     
----------- ----- ----------- ---------- ----- ------------------------------------------
GRANDPARENT 1     GRANDPARENT PARENT     FKP1  ->GRANDPARENT->PARENT                     
GRANDPARENT 2     PARENT      CHILD      FK1   ->GRANDPARENT->PARENT->CHILD              
GRANDPARENT 3     CHILD       GRANDCHILD FK3   ->GRANDPARENT->PARENT->CHILD->GRANDCHILD  
GRANDPARENT 1     GRANDPARENT PARENT2    FKP2  ->GRANDPARENT->PARENT2                    
GRANDPARENT 2     PARENT2     CHILD      FK2   ->GRANDPARENT->PARENT2->CHILD             
GRANDPARENT 3     CHILD       GRANDCHILD FK3   ->GRANDPARENT->PARENT2->CHILD->GRANDCHILD 
GRANDPARENT 2     PARENT2     GRANDCHILD FK4   ->GRANDPARENT->PARENT2->GRANDCHILD

Примечание: Этот запрос отобразит все уникальные маршруты от заданной корневой таблицы до каждой таблицы, являющейся ее потомком. Если RI-маршрут имеет ромбовидную форму, то в результирующих данных будут показаны оба маршрута. Как можно увидеть в предыдущем примере, показано оба следующих маршрута.

  • GRANDPARENT->PARENT->CHILD->GRANDCHILD
  • GRANDPARENT->PARENT2->CHILD->GRANDCHILD

Использование иерархических запросов имеет следующие преимущества относительно использования традиционных рекурсивных запросов.

  • Конструкции START WITH и CONNECT BY осуществляют рекурсию естественным образом, без необходимости написания рекурсивного запроса.
  • Псевдостолбец LEVEL автоматически возвращает номер уровня таблицы, начиная от корневого родителя.
  • Скалярная функция sys_connect_by_path () создает строку, представляющую маршрут от корня к узлу в иерархических запросах. В предыдущем примере эта функция используется в столбце CHAIN для построения цепочки RI-отношения от корневой таблицы.
  • При наличии какого-либо RI-цикла, например, GP → P1 → C12 → GP, конструкция NOCYCLE позволяет направить рекурсию таким образом, чтобы проигнорировать дублирующиеся строки в цикле.

Отображение отношения внешнего ключа для дочерних элементов и потомков всех таблиц в базе данных, не имеющей RI-циклов

Если в базе данных нет RI-циклов, можно изменить общее табличное выражение root_parents таким образом, чтобы включить все таблицы, имеющие не менее одного потомка, но не имеющие родителя (см. запрос Query 2 в Листинге 6).

Листинг 6. Запрос Query 2
with 
root_parents (root_parent_schema, root_parent_name) AS
 (select tabschema, tabname
    from syscat.tables
    where parents = 0 and children > 0)
select 
  substr(connect_by_root reftabname,1,11) as root,
  substr (level, 1,5) as lvl,
--  substr(reftabschema,1,6) as parent_schema,
  substr(reftabname,1,11) as parent, 
--  substr(tabschema,1,6) as child_schema,
  substr(tabname,1,10) as child, 
  substr(constname,1,5) as cnst, 
  substr(sys_connect_by_path(reftabname, '->') || '->' || 
  substr(tabname,1,20),1,42) as chain
from syscat.references
start with (reftabschema,reftabname) in (select root_parent_schema, 
                                        root_parent_name from root_parents)
connect by prior  tabname = reftabname and tabschema = reftabschema;

Однако запрос Query 2 не будет включать таблицы, которые находятся внутри RI-цикла, поскольку у таких таблиц количество родителей и количество потомков не равны нулю.


Отображение отношений внешнего ключа дочерних элементов и потомков, которые могут иметь RI-циклы

С вводом корневых таблиц в RI-циклах силами пользователя

С точки зрения бизнес-логики некоторые таблицы в RI-цикле лучше других подходят на роль корневой родительской таблицы в RI-цикле. Однако для базы данных нелегко определить, какая таблица в RI-цикле должна являться корневой родительской таблицей.

Если в системе не имеется избыточного количества RI-циклов, можно написать полуавтоматический запрос с ручным заданием одной таблицы в каждом RI-цикле в качестве корневой родительской таблицы.

В запросе Query 3 (см. Листинг 7) в операции UNION ALL в общем табличном выражении root_parents с целью ручного задания корневой таблицы в каждом RI-цикле добавлена конструкция VALUES, в результате чего запрос возвращает всех RI-потомков в базе данных.

Листинг 7. Запрос Query 3
with 
root_parents (root_parent_schema, root_parent_name) AS
 (select tabschema, tabname
    from syscat.tables
    where parents = 0 and children > 0
  UNION ALL
  select * from table(values ('NEWTON', 'GP'), ('NEWTON', 'SELF')))
select 
  substr(connect_by_root reftabname,1,11) as root,
  substr (level, 1,3) as lvl,
--  substr(reftabschema,1,6) as parent_schema,
  substr(reftabname,1,11) as parent, 
--  substr(tabschema,1,6) as child_schema,
  substr(tabname,1,10) as child, 
  substr(constname,1,7) as cnstnam, 
  substr(sys_connect_by_path(reftabname, '->') || '->' || 
  substr(tabname,1,20),1,42) as chain
from syscat.references
start with (reftabschema,reftabname) in (select root_parent_schema, 
                                        root_parent_name from root_parents)
connect by NOCYCLE prior  tabname = reftabname and tabschema = reftabschema;

Результаты выполнения запроса показаны в Листинге 8.

Листинг 8. Выходная информация запроса Query 3
ROOT        LVL PARENT      CHILD      CNSTNAM CHAIN                                     
----------- --- ----------- ---------- ------- ------------------------------------------
SELF        1   SELF        SELF       FK_SELF ->SELF->SELF                              
GRANDPARENT 1   GRANDPARENT PARENT     FKP1    ->GRANDPARENT->PARENT                     
GRANDPARENT 2   PARENT      CHILD      FK1     ->GRANDPARENT->PARENT->CHILD              
GRANDPARENT 3   CHILD       GRANDCHILD FK3     ->GRANDPARENT->PARENT->CHILD->GRANDCHILD  
GRANDPARENT 1   GRANDPARENT PARENT2    FKP2    ->GRANDPARENT->PARENT2                    
GRANDPARENT 2   PARENT2     CHILD      FK2     ->GRANDPARENT->PARENT2->CHILD             
GRANDPARENT 3   CHILD       GRANDCHILD FK3     ->GRANDPARENT->PARENT2->CHILD->GRANDCHILD 
GRANDPARENT 2   PARENT2     GRANDCHILD FK4     ->GRANDPARENT->PARENT2->GRANDCHILD        
GP          1   GP          P1         FKP1    ->GP->P1                                  
GP          2   P1          C11        FKC11   ->GP->P1->C11                             
GP          2   P1          C12        FKC12   ->GP->P1->C12                             
GP          3   C12         GP         FKGP1   ->GP->P1->C12->GP

Без ввода корневых таблиц в RI-циклах силами пользователя

Если вы предпочитаете полную автоматизацию и не волнуетесь о том, какая таблица в RI-цикле выбрана в качестве корневой таблицы (до тех пор, пока от каждого RI-цикла включено по одному представителю), то следующая процедура сохранит в качестве представителя по одной таблице от каждого RI-цикла во временной таблице под названием CYCLEROOTS. В конечном итоге эта процедура использует имена таблиц, сохраненные в CYCLEROOTS (см. Листинг 8), для отображения всех RI-цепочек в базе данных (см. Листинг 9).

Листинг 9. Запрос Query 3 для отображения всех RI-цепочек
-- If needed, create the user temporary tablespace for the temporary table.
CREATE BUFFERPOOL BUFFERPOOL4K  PAGESIZE 4K;
CREATE USER TEMPORARY TABLESPACE STMPTSP4 PAGESIZE 4K  BUFFERPOOL BUFFERPOOL4K;
                
-- create the temporary table to store one representative from each RI cycle as root
create GLOBAL TEMPORARY TABLE SESSION.CYCLEROOTS (SCHEMANAME VARCHAR(128),  
                                                  TABNAME VARCHAR(128));
                
--#SET TERMINATOR @
-- procedure to display RI chains in the database
CREATE PROCEDURE newton.FIND_RI_CHAINS ()
DETERMINISTIC 
NO EXTERNAL ACTION
DYNAMIC RESULT SETS 1
BEGIN
    DECLARE CYCLESCHEMA VARCHAR(128);
    DECLARE CYCLETABLE VARCHAR(128);
    DECLARE ROWS_FETCHED BIGINT;
    DECLARE C_CYCLETABLES CURSOR;
                
    -- This query will return the final result set after
    -- temporary table SESSION.CYCLEROOTS has been populated.
    DECLARE C_RESULTS CURSOR WITH RETURN TO CLIENT FOR
    WITH 
    ROOT_PARENTS (ROOT_PARENT_SCHEMA, ROOT_PARENT_NAME) AS
        (SELECT TABSCHEMA, TABNAME
            FROM SYSCAT.TABLES
            WHERE PARENTS = 0 AND CHILDREN > 0
        UNION ALL
        SELECT * FROM SESSION.CYCLEROOTS),
    HIERARCHY (ROOT, LEVEL, REFTABSCHEMA, REFTABNAME, TABSCHEMA, TABNAME, 
               CONSTNAME, CHAIN) AS
        (SELECT
            CONNECT_BY_ROOT REFTABNAME,
            LEVEL, 
            REFTABSCHEMA AS P_SCHEMA,
            REFTABNAME AS PARENT, 
            TABSCHEMA AS C_SCHEMA,
            TABNAME AS CHILD, 
            CONSTNAME AS CNSTNAM, 
            SUBSTR(SYS_CONNECT_BY_PATH(REFTABNAME, '->') || '->' || 
            SUBSTR(TABNAME,1,20),1,42) AS CHAIN
        FROM SYSCAT.REFERENCES
        START WITH (REFTABSCHEMA,REFTABNAME) IN (SELECT ROOT_PARENT_SCHEMA,
                                                 ROOT_PARENT_NAME
                                                 FROM ROOT_PARENTS)
        CONNECT BY NOCYCLE PRIOR  TABNAME = REFTABNAME AND TABSCHEMA =
         REFTABSCHEMA)
    SELECT
        SUBSTR(H.root,1,11) AS ROOT,
        CAST (H.LEVEL AS CHAR(2)) as LVL,
--       SUBSTR(H.REFTABSCHEMA,1,6) as P_SCHEMA,
        SUBSTR(H.REFTABNAME,1,11) as PARENT, 
--       SUBSTR(H.TABSCHEMA,1,6) as C_SCHEMA,
        SUBSTR(H.TABNAME,1,10) as CHILD, 
        SUBSTR(H.CONSTNAME,1,7) as CNSTNAM, 
        SUBSTR(H.CHAIN,1,42) as CHAIN
        FROM HIERARCHY H;

        -- initialize temporary table
        DELETE FROM SESSION.CYCLEROOTS;

        -- this query will return the remaining tables that are in RI cycles
        SET C_CYCLETABLES = CURSOR FOR
            WITH 
                ROOT_PARENTS (ROOT_PARENT_SCHEMA, ROOT_PARENT_NAME) AS
                  (SELECT TABSCHEMA, TABNAME
                    FROM SYSCAT.TABLES
                    WHERE PARENTS = 0 AND CHILDREN > 0
                   UNION ALL
                   SELECT * FROM SESSION.CYCLEROOTS),
                HIERARCHY (ROOT, LEVEL, REFTABSCHEMA, REFTABNAME, TABSCHEMA, 
                           TABNAME, CONSTNAME, CHAIN) AS
                (SELECT CONNECT_BY_ROOT REFTABNAME AS ROOT, LEVEL, 
                    REFTABSCHEMA AS PARENT_SCHEMA,
                    REFTABNAME AS PARENT, 
                    TABSCHEMA AS CHILD_SCHEMA,
                    TABNAME AS CHILD, 
                    CONSTNAME AS CONSTNAME, 
                    SUBSTR(SYS_CONNECT_BY_PATH(REFTABNAME, '->') || '->' || 
                    SUBSTR(TABNAME,1,20),1,50) AS CHAIN
                FROM SYSCAT.REFERENCES
                START WITH (REFTABSCHEMA,REFTABNAME) IN (SELECT ROOT_PARENT_SCHEMA,
                                                ROOT_PARENT_NAME FROM ROOT_PARENTS)
                CONNECT BY NOCYCLE PRIOR  TABNAME = REFTABNAME AND 
                                          TABSCHEMA =  REFTABSCHEMA)
            SELECT TABSCHEMA, TABNAME
                FROM SYSCAT.TABLES
                WHERE CHILDREN > 0
            EXCEPT
                SELECT REFTABSCHEMA, REFTABNAME  FROM HIERARCHY H;

        OPEN C_CYCLETABLES;

        -- Just select the first table as a root table from the remaining tables that are 
        -- in RI cycles
        FETCH C_CYCLETABLES INTO CYCLESCHEMA, CYCLETABLE;

        SET ROWS_FETCHED = CURSOR_ROWCOUNT(C_CYCLETABLES);

        -- Keep looping until the result set from C_CYCLETABLES is empty.
        WHILE (ROWS_FETCHED > 0) DO

            -- insert the select representative into temporary table SESSION.CYCLEROOTS 
            INSERT INTO SESSION.CYCLEROOTS VALUES (CYCLESCHEMA, CYCLETABLE);

            CLOSE C_CYCLETABLES;

            -- restart the cursor.  The result set will be different from the 
            -- the previous iterations of the loop.  All the tables that
            -- are in the same RI cycle as the newly added representative
            -- will not show up in the result set from the next iteration of the
            -- loop.
            OPEN C_CYCLETABLES;

            FETCH FROM C_CYCLETABLES INTO CYCLESCHEMA, CYCLETABLE;

            SET ROWS_FETCHED = CURSOR_ROWCOUNT(C_CYCLETABLES);

        END WHILE;

        CLOSE C_CYCLETABLES;

        -- When the loop exits, one representative from each RI cycle will have
        -- been added to the temporary table SESSION.CYCLEROOTS.  We will now 
        -- open C_RESULTS using the populated temporary table SESSION.CYCLEROOTS.

        OPEN C_RESULTS;

END@
--#SET TERMINATOR ;

CALL newton.FIND_RI_CHAINS();

DROP TABLE  SESSION.CYCLEROOTS;

Результаты выполнения запроса показаны в Листинге 10.

Листинг 10. Запрос Query 3 для отображения выходной информации всех RI-цепочек
Result set 1
--------------
                
ROOT       LVL PARENT      CHILD      CNSTNAM CHAIN                                     
---------- --- ----------- ---------- ------- ------------------------------------------
SELF        1  SELF        SELF       FK_SELF ->SELF->SELF                              
GRANDPARENT 1  GRANDPARENT PARENT     FKP1    ->GRANDPARENT->PARENT                     
GRANDPARENT 2  PARENT      CHILD      FK1     ->GRANDPARENT->PARENT->CHILD              
GRANDPARENT 3  CHILD       GRANDCHILD FK3     ->GRANDPARENT->PARENT->CHILD->GRANDCHILD  
GRANDPARENT 1  GRANDPARENT PARENT2    FKP2    ->GRANDPARENT->PARENT2                    
GRANDPARENT 2  PARENT2     CHILD      FK2     ->GRANDPARENT->PARENT2->CHILD             
GRANDPARENT 3  CHILD       GRANDCHILD FK3     ->GRANDPARENT->PARENT2->CHILD->GRANDCHILD 
GRANDPARENT 2  PARENT2     GRANDCHILD FK4     ->GRANDPARENT->PARENT2->GRANDCHILD        
C12         1  C12         GP         FKGP1   ->C12->GP                                 
C12         2  GP          P1         FKP1    ->C12->GP->P1                             
C12         3  P1          C11        FKC11   ->C12->GP->P1->C11                        
C12         3  P1          C12        FKC12   ->C12->GP->P1->C12   
                
12 record(s) selected.
                
Return Status = 0

Обратите внимание, что таблица C12 была выбрана в качестве представителя RI-цикла GP->P1->C12->GP.


Заключение

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

Ресурсы

Научиться

Обсудить

  • Присоединяйтесь к сообществу My developerWorks community. Подключитесь к другим пользователям developerWorks, а также ознакомьтесь с ориентированными на разработчиков форумами, блогами, группами и вики-ресурсами.

Комментарии

developerWorks: Войти

Обязательные поля отмечены звездочкой (*).


Нужен IBM ID?
Забыли Ваш IBM ID?


Забыли Ваш пароль?
Изменить пароль

Нажимая Отправить, Вы принимаете Условия использования developerWorks.

 


Профиль создается, когда вы первый раз заходите в developerWorks. Информация в вашем профиле (имя, страна / регион, название компании) отображается для всех пользователей и будет сопровождать любой опубликованный вами контент пока вы специально не укажите скрыть название вашей компании. Вы можете обновить ваш IBM аккаунт в любое время.

Вся введенная информация защищена.

Выберите имя, которое будет отображаться на экране



При первом входе в developerWorks для Вас будет создан профиль и Вам нужно будет выбрать Отображаемое имя. Оно будет выводиться рядом с контентом, опубликованным Вами в developerWorks.

Отображаемое имя должно иметь длину от 3 символов до 31 символа. Ваше Имя в системе должно быть уникальным. В качестве имени по соображениям приватности нельзя использовать контактный e-mail.

Обязательные поля отмечены звездочкой (*).

(Отображаемое имя должно иметь длину от 3 символов до 31 символа.)

Нажимая Отправить, Вы принимаете Условия использования developerWorks.

 


Вся введенная информация защищена.


  • Bluemix

    Узнайте больше информации о платформе IBM Bluemix, создавайте приложения, используя готовые решения!

  • developerWorks Premium

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

  • Библиотека документов

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

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=40
Zone=Information Management
ArticleID=937008
ArticleTitle=Рекомендации по использованию SQL-запросов для нахождения отношений внешнего ключа
publish-date=07102013