Select within select where condition exists

Asked

Viewed 171 times

3

Good morning,

With a table of articles with the fields

Reference | Quantity | Price | Referencesociated |

I wanted to have a select that would do the following, with the example:

Example Table of Articles

Article 1: X - 2 - 1€ - A, B
Article 2: Y - 5 - 2€ - C
Artigo3: A - 1 - 5€ - NULL
Article 4: B - 7 - 3€ - NULL
Artigo5: C - 4 - 4€ - NULL

Desired result of the query:

Reference | Quantity | Price |

X | 2 | 1€ |
A | 1 | 5€ |
B | 7 | 3€ |
Y | 5 | 2€ |
C | 4 | 4€ |

If the reference has associated references, it creates underscores with the fields of each associated reference. How can I do this?

  • That column of yours ReferenciasAssociadas is a text field? If yes the table design is already bad

  • This is just an example and it’s not the real case where I’m going to apply this, the actual table design isn’t like this.

  • Only this influences the answer. You have a column only with the keys or you have another table that relates the other codes?

  • Detailing, I have a table articles where you have quantity and price information. I have a table of associated references where for example there are 2 lines (reference A and B). The foreign key between these two tables is the reference.

  • Beauty, it makes the answer easier

2 answers

2

Considering the following structure:

CREATE TABLE artigos (
  referencia VARCHAR(1),
  quantidade INTEGER,
  preco      NUMERIC(15, 2)

);

INSERT INTO artigos(referencia, quantidade, preco)
            VALUES ('X', 2, 1.0),
                   ('Y', 5, 2.0),
                   ('A', 1, 5.0),
                   ('B', 7, 3.0),
                   ('C', 4, 4.0);

CREATE TABLE associadas(
  referencia VARCHAR(1),
  associada VARCHAR(1)
);

INSERT INTO associadas(referencia, associada)
               VALUES ('X', 'A'),
                      ('X', 'B'),
                      ('Y', 'C');

To query to get the result you want would be:

SELECT x.referencia,
       x.quantidade,
       x.preco
  FROM (
    SELECT art.referencia AS aux,
           art.referencia,
           art.quantidade,
           art.preco
      FROM artigos art
     WHERE EXISTS(SELECT 1
                    FROM associadas ass
                   WHERE ass.referencia = art.referencia)
    UNION
    SELECT ass.referencia AS aux,
           art.referencia,
           art.quantidade,
           art.preco
      FROM artigos art
     INNER JOIN associadas ass ON ass.associada = art.referencia
) x
ORDER BY x.aux,
         CASE x.aux
           WHEN x.referencia THEN 0
           ELSE 1
         END;

In the query above we would link the records to those that are hierarchically larger and we would sort by that relation.

Or by simplifying:

SELECT art.referencia,
       art.quantidade,
       art.preco
  FROM artigos art
  LEFT JOIN associadas ass ON ass.associada = art.referencia
 ORDER BY COALESCE(ass.referencia, art.referencia),
          CASE
            WHEN ass.referencia IS NULL THEN 0
            ELSE 1
          END

The result would be:

| referencia | quantidade | preco |
| ---------- | ---------- | ----- |
| X          | 2          | 1     |
| A          | 1          | 5     |
| B          | 7          | 3     |
| Y          | 5          | 2     |
| C          | 4          | 4     |

You can check the result in DB Fiddle for the first example or for the second example.

  • What can I do when for example the fields in common are just the Reference? For example, the Articles table has the fields Reference, Quantity, Price and the Associated table has only Reference and Associated Reference. And I need to do this with a CTE.

  • @Diogofernandes Your original question has already been answered with this answer. The suggestion I give you is to accept the answer and ask another question explaining in detail your new question.

0

Here’s a suggestion that uses nonrecursive CTE.

-- código #1
with ctePai as (
SELECT A.Referencia, A.Quantidade, A.Preco, A.Referencia as Pai, 0 as Tag
  from tabArtigos as A
  where not exists (SELECT * from tabAssociação as B where B.RefAssociada = A.Referencia)

union all

SELECT C.RefAssociada, D.Quantidade, D.Preco, C.Referencia, 1
  from tabAssociação as C
       inner join tabArtigos as D on D.Referencia = C.RefAssociada
)
SELECT Referencia, Quantidade, Preco  --, Pai, Tag
  from ctePai 
  order by Pai, Tag;

To test, I used the following structure/data:

-- código #2
CREATE TABLE tabArtigos (
  Referencia char(1) not null primary key,
  Quantidade tinyint,
  Preco money
);

INSERT into tabArtigos (Referencia, Quantidade, Preco) values
     ('X', 2, 1), ('Y', 5, 2), ('A', 1, 5),
     ('Z', 3, 2.1), ('B', 7, 3), ('C', 4, 4);

CREATE TABLE tabAssociação (
  Referencia char(1) not null references tabArtigos (Referencia),
  RefAssociada char(1) not null references tabArtigos (Referencia)
);

INSERT into tabAssociação (Referencia, RefAssociada) values
     ('X', 'A'), ('X', 'B'), ('Y', 'C');

Note that in the data was added line with Reference value ('Z'), which has no subreferences and is not sub-reference of other.

  • In SELECT when we call the Reference field by which is it fetched in CTE? In my real case, in the article table the name of the reference field is "ref" and in my association table the reference field is "refb"

  • Diogo, when union (UNION or UNION ALL) is used, the final names of the columns are the same as defined in the first union SELECT (unless column names are defined in CTE). In the CTE ctePai, the first column is called Reference, even if the second SELECT of the union is the Refassociated column.

  • What can I do when for example the fields in common are just the Reference? For example, the Articles table has the Reference, Quantity, Preco fields and the Tabassociation table has only Reference and Associated Reference.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.