Выборка из таблиц со связью Many To Many

387
30 августа 2017, 14:20

в БД PostgreSQL есть таблица Provider со строками id и name. Также есть таблица Currencies с полями id и currency, и Countries с полями id и country. Между Provider и Currencies, и Provider и Countries связь Many to Many, соответственно есть 2 таблицы ссылок provcurr и provcountries. Каждому провайдеру может соответствовать произвольное количество countries и currencies.

Задача состоит в том, чтобы прочитать из таблицы провайдеров с заданной страной и вернуть в виде списка.

Выглядит это на данный момент как-то так:

private static String SELECT_BY_COUNTRY = "SELECT * " +
        "                                           FROM provider " +
        "                                           INNER JOIN provcurr" +
        "                                           ON provider.id = provcurr.idprov" +
        "                                           INNER JOIN provider_curr " +
        "                                           ON provider_curr.id = idcurr" +
        "                                           INNER JOIN provcountry" +
        "                                           ON provider.id = provcountry.idprov" +
        "                                           INNER JOIN provider_country" +
        "                                           ON provider_country.id = idcountry" +
        "                                           WHERE country = ?";

public ArrayList<Provider> select(Country country) {
    ArrayList<Provider> result = null;
    try {
        preparedStatement = connection.prepareStatement(SELECT_BY_COUNTRY);
        preparedStatement.setString(1, country.toString());
        ResultSet provider = preparedStatement.executeQuery();
        result = createProviderList(provider);
        System.out.println(result);
        System.out.println("All providers was selected from database");
        System.out.println("Generating provider's list");
    } catch (SQLException e) {
        System.err.println("Unable to select providers \n" + e.toString());
    } finally {
        return result;
    }
}
private ArrayList<Provider> createProviderList(ResultSet provider) throws SQLException {
    Map<String, Provider> providers = new HashMap<>();
    while (provider.next()) {
        String providerName = provider.getString("name");
        if (!providers.containsKey(providerName)) {
            providers.put(providerName, new Provider(providerName, new ArrayList<>(), new ArrayList<>()));
        }
        if (!providers.get(providerName).containsCurrencsy(provider.getString("currency"))) {
            providers.get(providerName).addCurrency(provider.getString("currency"));
        }
        if (!providers.get(providerName).containsCountry(provider.getString("country"))) {
            providers.get(providerName).addCountry(provider.getString("country"));
        }
    }
    System.out.println("List was generated");
    return new ArrayList<Provider>(providers.values());
}

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

Собственно вопрос - как одним запросом получить провайдеров, которым соответствует заданная страна со списком всех остальных стран и валют?

Схема таблиц (стрелка от provcurr к provider в другую сторону):

Answer 1

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

CREATE TABLE "provider"  ( 
"id"    int NOT NULL,
"name"  varchar(25) NOT NULL 
);
CREATE TABLE "provcountries"  ( 
    "idprov"    int NOT NULL,
    "idcountry" int NOT NULL 
    );
CREATE TABLE "provcurr"  ( 
    "idprov"    int NOT NULL,
    "idcurr"    int NOT NULL 
    );
CREATE TABLE "provider_curr"  ( 
    "id"        int NOT NULL,
    "currency"  varchar(25) NOT NULL 
    );
CREATE TABLE "provider_сountry"  ( 
    "id"        int NULL,
    "country"   varchar(25) NULL 
    );

INSERT INTO provider VALUES (1, 'provider1');
INSERT INTO provider VALUES (2, 'provider2');
INSERT INTO provider VALUES (3, 'provider3');
INSERT INTO provider_curr VALUES (1, 'currency1');
INSERT INTO provider_curr VALUES (2, 'currency2');
INSERT INTO provider_curr VALUES (3, 'currency3');
INSERT INTO provider_сountry VALUES (1, 'country1');
INSERT INTO provider_сountry VALUES (2, 'country2');
INSERT INTO provider_сountry VALUES (3, 'country3');
INSERT INTO provcountries VALUES (1, 1);
INSERT INTO provcountries VALUES (1, 2);
INSERT INTO provcountries VALUES (2, 3);
INSERT INTO provcountries VALUES (3, 1);
INSERT INTO provcurr VALUES (1, 1);
INSERT INTO provcurr VALUES (1, 2);
INSERT INTO provcurr VALUES (2, 3);
INSERT INTO provcurr VALUES (3, 2);
SELECT
    p.id            AS provider_id,
    p.name          AS provider_name,
    cur.idcurr      AS currency_id,
    cur.currency    AS currency_name,
    co.idcountry    AS country_id,
    co.country      AS country_name
FROM
    ( SELECT id, name FROM provider WHERE id IN (SELECT idprov FROM provcountries WHERE idcountry = 1) ) AS p
    LEFT JOIN
    ( SELECT idprov, idcountry, country FROM provcountries pco JOIN provider_сountry co ON (co.id = pco.idcountry)) AS co
    ON (p.id = co.idprov)
    LEFT JOIN
    ( SELECT idprov, idcurr, currency FROM  provcurr pcr JOIN provider_curr cr ON (cr.id = pcr.idcurr) ) AS cur
    ON (p.id = cur.idprov)

Результат:

provider_id;provider_name;currency_id;currency_name;country_id;country_name
1;provider1;1;currency1;2;country2
1;provider1;2;currency2;2;country2
1;provider1;1;currency1;1;country1
1;provider1;2;currency2;1;country1
3;provider3;2;currency2;1;country1
READ ALSO
Как защитить исходный код?

Как защитить исходный код?

Нужно сделать так, чтоб apk файл нельзя было прочитать

314
JSON to Object MyBatis

JSON to Object MyBatis

В базе PosgreSQL есть колонка с jsonb, я хочу получить содержимое этой колонки не как строку, а как объект(преобразовать json в объект на лету, чтобы...

350
Изменение значения переменной

Изменение значения переменной

Имеется следующий код:

265
Подбор ресурсов для разных экранов для android приложения

Подбор ресурсов для разных экранов для android приложения

Здравствуйте, я начинающий android-разработчикУ меня имеется приложение, которое я хочу адаптировать под различные устройства

251