The joint missing! PDF Print E-mail
User Rating: / 0
PoorBest 
Wednesday, 28 May 2008

Preamble
Given the problems that I regularly ask colleagues and users, I have tried to solve the case of a family problems rather difficult to express in SQL simple. I came to the conclusion that it was interesting to foresee adding a new SQL join type, the seam "LINEAR". We will as a first step pose different problems and see how we can solve this by introducing new operator.

In the immediate I do not venture into the relational algebra to determine whether the good doctor Codd has failed at its task. I therefore reserve the theorists a great battle in perspective to determine whether this operation and how to represent ...
PLEASE: you can have the english translation of this paper by clicking HERE
1. Number lines and all queries arising
Either the table T_CLIENT_CLI (CLI_ID, CLI_NOM) as follows:
CLI_ID CLI_NOM
------- ------------
17 DURAND
192 DUPONT
44 DUVAL
11 DUMOULIN
741 DULIN
82 DUPOND
177 DURAND
Creation of the test Thursday:
CREATE TABLE T_CLIENT_CLI (CLI_ID INTEGER, CLI_NOM VARCHAR (10)) INSERT INTO T_CLIENT_CLI (CLI_ID, CLI_NOM) VALUES (17, 'DURAND') INSERT INTO T_CLIENT_CLI (CLI_ID, CLI_NOM) VALUES (192, 'DUPONT') INSERT INTO T_CLIENT_CLI (CLI_ID , CLI_NOM) VALUES (44, 'DUVAL') INSERT INTO T_CLIENT_CLI (CLI_ID, CLI_NOM) VALUES (11, 'DUMOULIN') INSERT INTO T_CLIENT_CLI (CLI_ID, CLI_NOM) VALUES (741, 'DULIN') INSERT INTO T_CLIENT_CLI (CLI_ID, CLI_NOM ) VALUES (82, 'DUPOND') INSERT INTO T_CLIENT_CLI (CLI_ID, CLI_NOM) VALUES (177, 'DURAND')

The question is: how to get a response the names of our customers in alphabetical order with their rank (from 1 to n)?

1.1. RESPONSE 1
If we apply strictly the issue, then the answer is:
CLI_NOM RANG
------------- -----
DULIN 1
DUMOULIN 2
DUPOND 3
DUPONT 4
DURAND 5
DURAND 5
DUVAL 7
Indeed, both located DURAND tie occupy the 5th place, while Duval has not the 6th, but the 7th row!

1.2. ANSWER 2
Another possible solution is:
CLI_NOM RANG
------------- -----
DULIN 1
DUMOULIN 2
DUPOND 3
DUPONT 4
DURAND 5
DURAND 6
DUVAL 7
This means a frank and direct numbering regardless of duplication or ambiguity selected information. It's a bit what are the columns of auto increment of certain RDBMS.

1.3. RESPONSE 3
Finally we can refine the latter solution by introducing a counting to eliminate duplication:

CLI_NOM RANG NUMBER
------------- ----- ------
DULIN 1 1
DUMOULIN 2 1
DUPOND 3 1
DUPONT 4 1
DURAND 5 2
DUVAL 7 1
Who deserves to be more clean match, however, the initial application!

1.4. ANSWER 4
By pushing things to extremes, it may require that the numbering category is strict and without "hole", like this:
CLI_NOM RANG NUMBER
------------- ----- ------
DULIN 1 1
DUMOULIN 2 1
DUPOND 3 1
DUPONT 4 1
DURAND 5 2
DUVAL 6 1
But what are the applications necessary to achieve the various solutions proposed?

1.5. Queries
In principle, requests to meet such demand require auto non equivalent to join the enumeration of tuples whose values above the tuple underway.

Query the response 1:
SELECT T1.CLI_NOM, COUNT (T2.CLI_ID) + 1 AS RANK FROM T_CLIENT_CLI T1 LEFT OUTER JOIN T_CLIENT_CLI T2 ON T1.CLI_NOM> T2.CLI_NOM GROUP BY T1.CLI_ID, T1.CLI_NOM ORDER BY ROW

Query the answer 2:
SELECT T1.CLI_NOM, COUNT (T2.CLI_ID) + 1 AS RANK FROM T_CLIENT_CLI T1 LEFT OUTER JOIN T_CLIENT_CLI T2 ON T1.CLI_NOM | | CAST (T1.CLI_ID AS CHAR (16))> T2.CLI_NOM | | CAST (T2. CLI_ID AS CHAR (16)) GROUP BY T1.CLI_ID, T1.CLI_NOM ORDER BY ROW

Query the response 3:
SELECT T1.CLI_NOM, RANK, NAME FROM (SELECT DISTINCT T1.CLI_NOM, COUNT (T2.CLI_ID) + 1 AS RANK FROM T_CLIENT_CLI T1 LEFT OUTER JOIN T_CLIENT_CLI T2 ON T1.CLI_NOM> T2.CLI_NOM GROUP BY T1.CLI_ID, T1. CLI_NOM) T1 INNER JOIN (SELECT CLI_NOM, COUNT (CLI_ID) AS NUMBER FROM T_CLIENT_CLI T1 GROUP BY CLI_NOM) Q2 ON T1.CLI_NOM = T2.CLI_NOM ORDER BY ROW

Query the response 4:
SELECT T2.CLI_NOM, COUNT (T1.CLI_NOM) AS RANK, NAME FROM (CLI_NOM SELECT DISTINCT FROM T_CLIENT_CLI) T1 LEFT OUTER JOIN (CLI_NOM SELECT DISTINCT FROM T_CLIENT_CLI) Q2 ON T1.CLI_NOM <= T2.CLI_NOM INNER JOIN (SELECT CLI_NOM, COUNT (CLI_ID) AS NUMBER FROM T_CLIENT_CLI GROUP BY CLI_NOM) T3 ON T2.CLI_NOM = T3.CLI_NOM GROUP BY T2.CLI_NOM, T3.NOMBRE ORDER BY ROW

The least we can say is that this kind of requests is not in the spirit of starting. What then developer facing this problem in a context of tables far more extensive than our example? It is very likely that the latter passes by hand and lunges a nice stored procedure at best and at worst on the client!

2. Assign lines places
The second family problems that merit our attention in this context, the problems of employment, issues dear to all teachers at the beginning of the school year, for example. The question is: starting up a table and a population consisting of another place (each place is intended to accommodate a student, a spectator…) how to assign a place for every element of the population?

Reclaiming our table of customers and add a table seating model places a theatre T_PLACE_PLC (PLC_REF). The theater seats are numbered as you know by letters (rank) and figures (in rank order). For our demonstration we will limit to three ranks and 5 seats per row, ie a theater pocket!

PLC_REF
-------
A01
A02
A03
A04
A05
B01
B02
B03
B04
B05
C01
C02
C03
C04
C05
Creation of the test Thursday:
CREATE TABLE T_PLACE_PLC (PLC_REF CHAR (3)) INSERT INTO T_PLACE_PLC (PLC_REF) VALUES ( 'A01') INSERT INTO T_PLACE_PLC (PLC_REF) VALUES ( 'A02') INSERT INTO T_PLACE_PLC (PLC_REF) VALUES ( 'A03') INSERT INTO T_PLACE_PLC ( PLC_REF) VALUES ( 'A04') INSERT INTO T_PLACE_PLC (PLC_REF) VALUES ( 'A05') INSERT INTO T_PLACE_PLC (PLC_REF) VALUES ( 'B01') INSERT INTO T_PLACE_PLC (PLC_REF) VALUES ( 'B02') INSERT INTO T_PLACE_PLC (PLC_REF) VALUES ( 'B03') INSERT INTO T_PLACE_PLC (PLC_REF) VALUES ( 'B04') INSERT INTO T_PLACE_PLC (PLC_REF) VALUES ( 'B05') INSERT INTO T_PLACE_PLC (PLC_REF) VALUES ( 'C01') INSERT INTO T_PLACE_PLC (PLC_REF) VALUES ( 'C02') INSERT INTO T_PLACE_PLC (PLC_REF) VALUES ( 'C03') INSERT INTO T_PLACE_PLC (PLC_REF) VALUES ( 'C04') INSERT INTO T_PLACE_PLC (PLC_REF) VALUES ( 'C05')

The problem could not be simpler: how to allocate customers in the first seats?
It seems clear that the simplest solution would be numbered lines customers then the lines of seats and make a join with the numbering.
Something like:

CLI_ID CLI_NOM CLI_NUM
------------ ------- -------
17 DURAND 1
192 DUPONT 2
44 DUVAL 3
11 DUMOULIN 4
741 DULIN 5
82 DUPOND 6
177 DURAND 7
PLC_REF PLC_NUM
-------- -------
A01 1
A02 2
A03 3
A04 4
A05 5
B01 6
B02 7
B03 8
B04 9
B05 10
C01 11
C02 12
C03 13
C04 14
C05 15
Therefore, the solution is obvious:
SELECT CLI_NOM, PLC_REF FROM T_CLIENT_CLI JOIN T_PLACE_PLC ON CLI_NUM = PLC_NUM

Who gives:
CLI_NOM PLC_REF
------------ -------
DURAND A01
DUPONT A02
DUVAL A03
DUMOULIN A04
DULIN A05
DUPOND B01
DURAND B02
But we do not have these columns available… How?
Just apply what we have just seen in the previous example, for both customers, but also for chairs and join all on the columns of numbers generated.

I request the book as it stood, its development is quite happy!
SELECT CLI_NOM, PLC_REF FROM (SELECT T1.CLI_NOM, COUNT (T2.CLI_ID) + 1 AS RANK FROM T_CLIENT_CLI T1 LEFT OUTER JOIN T_CLIENT_CLI T2 ON T1.CLI_NOM | | CAST (T1.CLI_ID AS CHAR (16))> T2.CLI_NOM | | CAST (T2.CLI_ID AS CHAR (16)) GROUP BY T1.CLI_ID, T1.CLI_NOM) C INNER JOIN (SELECT T3.PLC_REF, COUNT (T4.PLC_REF) + 1 AS RANK FROM T_PLACE_PLC T3 LEFT OUTER JOIN T_PLACE_PLC T4 ON T3.PLC_REF> T4.PLC_REF GROUP BY T3.PLC_REF) P ON = P. C. RANK RANK

And yet we have taken into account that the column PLC_REF is a key candidate of the table T_PLACE_PLC ...

3. The solution, the seam line!
The primal condition is to have a very simple table with a single column and filled with the following numbers: T_I_ENT (ENT_I). Of course there will be limited for example to a range of 0 to 1000 or more as needed:
ENT_I
-------
0
1
2
3
4
5
6
7
8
9
10
...

CREATE TABLE T_I_ENT (ENT_I INTEGER) INSERT INTO T_I_ENT (ENT_I) VALUES (0) INSERT INTO T_I_ENT (ENT_I) VALUES (1) INSERT INTO T_I_ENT (ENT_I) VALUES (2) INSERT INTO T_I_ENT (ENT_I) VALUES (3) INSERT INTO T_I_ENT (ENT_I) VALUES (4) INSERT INTO T_I_ENT (ENT_I) VALUES (5) INSERT INTO T_I_ENT (ENT_I) VALUES (6) INSERT INTO T_I_ENT (ENT_I) VALUES (7) INSERT INTO T_I_ENT (ENT_I) VALUES (8) INSERT INTO T_I_ENT (ENT_I) VALUES (9) INSERT INTO T_I_ENT (ENT_I) VALUES (10) ... INSERT INTO T_I_ENT (ENT_I) VALUES (1000)

We note in passing that it is unnecessary to enter all the numbers from 1 to 1000, the first ten enough and a simple application integration will play the role of complementary insertion:
INSERT INTO T_I_ENT (ENT_I) SELECT DISTINCT I1.ENT_I + (I2.ENT_I * 10) + (I3.ENT_I * 100) FROM T_I_ENT I1 CROSS JOIN T_I_ENT I2 CROSS JOIN T_I_ENT I3 CROSS JOIN T_I_ENT I4 WHERE I1.ENT_I + (I2. ENT_I * 10) + (I3.ENT_I * 100) BETWEEN 1000 AND 0

Thus the juxtaposition of the projection by the name of the customer table ordered by the customer with the projection of the whole table ordered meets our expectations:
CLI_NOM T_I_ENT
---------- ------------
DULIN 1
DUMOULIN 2
DUPOND 3
DUPONT 4
DURAND 5
DURAND 6
DUVAL 7
That is why I propose the new operator join linear: LINEAR JOIN to match the line of a row of the table left, the line rang a + offset the table right and so forth.

4. Syntax and rules of the seam line
The seam line meets the following syntax:
SELECT <liste of selection> FROM <table left [LEFT | RIGHT] LINEAR JOIN <table droite> [OFFSET <offset value>]

In our previous example, you just have to do:
SELECT CLI_NOM, T_I_ENT FROM LINEAR T_CLIENT_CLI JOIN T_I_ENT OFFSET 1 / * Elimination of the first line, a zero * / ORDER BY CLI_NOM, T_I_ENT

Some explanations:
the key word OFFSET can tell from what line to take into account the first row of the table right associated with the first line of the table left
ORDER BY clause operates separately before the joint linear tables attached the joint can be left outside (LEFT JOIN LINEAR) or right (RIGHT JOIN LINEAR), but not on both sides. By default it is internal

Example join linear external right:
SELECT CLI_NOM, T_I_ENT FROM RIGHT T_CLIENT_CLI LINEAR JOIN T_I_ENT ORDER BY CLI_NOM, T_I_ENT

which gives:
CLI_NOM T_I_ENT
---------- ------------
DULIN 0
DUMOULIN 1
DUPOND 2
DUPONT 3
DURAND 4
DURAND 5
DUVAL 6
NULL 7
NULL 8
...
NULL 1000
To solve our problem of allocating places theatre, just do:
SELECT CLI_NOM, PLC_REF FROM LINEAR T_CLIENT_CLI JOIN T_I_ENT LINEAR JOIN T_PLACE_PLC ORDER BY CLI_NOM, T_I_ENT, PLC_REF

I do not know what you think but I find this writing simple and easy to understand!

5. CONCLUSION
These complaints are similar to the T-JOIN (théta joints) Dr. Codd to obtain an optimal correspondence inequalities (typically the problem of allocating students in rooms capacity data).
I leave it to your sagacity representation of such a joint in relational algebra!

 
< Prev   Next >
School Joomla Templates and Joomla Tutorials