Соединение выбора SQL: действительно ли возможно снабдить префиксом все столбцы как 'префикс.*'?

Я понимаю, что это очень старое сообщение и уже есть отличные ответы, но я хотел сделать простой MCVE, чтобы продемонстрировать один такой подход и позволить новым кодеру быстро увидеть концепцию в действии.

В этом примере мы будем использовать 5 файлов:

  1. Main.java - просто используется для запуска приложения и вызова первого контроллера.
  2. Controller1.java - контроллер для первого макета FXML.
  3. Controller2.java - контроллер для второго макета FXML.
  4. Layout1.fxml - макет FXML для первого сцена.
  5. Layout2.fxml - макет FXML для второй сцены.

Все файлы перечислены полностью в нижней части этого сообщения.

Цель: показать переданные значения от Controller1 до Controller2 и наоборот.

Поток программы:

  • Первая сцена содержит TextField, Button и Label. Когда щелчок Button щелкнут, второе окно загружается и отображается, включая текст, введенный в TextField.
  • Внутри второй сцены есть также TextField, Button , и Label. Label отобразит текст, введенный в TextField на первой сцене.
  • При вводе текста во второй сцене TextField и нажатии Button первая сцена Label сцены обновлен, чтобы показать введенный текст.

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

Сам код также комментируется некоторые детали того, что происходит и как.

КОД

Main.java:

import javafx.application.Application;
import javafx.stage.Stage;

public class Main extends Application {

    public static void main(String[] args) {
        launch(args);
    }

    @Override
    public void start(Stage primaryStage) {

        // Create the first controller, which loads Layout1.fxml within its own constructor
        Controller1 controller1 = new Controller1();

        // Show the new stage
        controller1.showStage();

    }
}

Controller1.java:

import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.stage.Stage;

import java.io.IOException;

public class Controller1 {

    // Holds this controller's Stage
    private final Stage thisStage;

    // Define the nodes from the Layout1.fxml file. This allows them to be referenced within the controller
    @FXML
    private TextField txtToSecondController;
    @FXML
    private Button btnOpenLayout2;
    @FXML
    private Label lblFromController2;

    public Controller1() {

        // Create the new stage
        thisStage = new Stage();

        // Load the FXML file
        try {
            FXMLLoader loader = new FXMLLoader(getClass().getResource("Layout1.fxml"));

            // Set this class as the controller
            loader.setController(this);

            // Load the scene
            thisStage.setScene(new Scene(loader.load()));

            // Setup the window/stage
            thisStage.setTitle("Passing Controllers Example - Layout1");

        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * Show the stage that was loaded in the constructor
     */
    public void showStage() {
        thisStage.showAndWait();
    }

    /**
     * The initialize() method allows you set setup your scene, adding actions, configuring nodes, etc.
     */
    @FXML
    private void initialize() {

        // Add an action for the "Open Layout2" button
        btnOpenLayout2.setOnAction(event -> openLayout2());
    }

    /**
     * Performs the action of loading and showing Layout2
     */
    private void openLayout2() {

        // Create the second controller, which loads its own FXML file. We pass a reference to this controller
        // using the keyword [this]; that allows the second controller to access the methods contained in here.
        Controller2 controller2 = new Controller2(this);

        // Show the new stage/window
        controller2.showStage();

    }

    /**
     * Returns the text entered into txtToSecondController. This allows other controllers/classes to view that data.
     */
    public String getEnteredText() {
        return txtToSecondController.getText();
    }

    /**
     * Allows other controllers to set the text of this layout's Label
     */
    public void setTextFromController2(String text) {
        lblFromController2.setText(text);
    }
}

Controller2.java:

import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.stage.Stage;

import java.io.IOException;

public class Controller2 {

    // Holds this controller's Stage
    private Stage thisStage;

    // Will hold a reference to the first controller, allowing us to access the methods found there.
    private final Controller1 controller1;

    // Add references to the controls in Layout2.fxml
    @FXML
    private Label lblFromController1;
    @FXML
    private TextField txtToFirstController;
    @FXML
    private Button btnSetLayout1Text;

    public Controller2(Controller1 controller1) {
        // We received the first controller, now let's make it usable throughout this controller.
        this.controller1 = controller1;

        // Create the new stage
        thisStage = new Stage();

        // Load the FXML file
        try {
            FXMLLoader loader = new FXMLLoader(getClass().getResource("Layout2.fxml"));

            // Set this class as the controller
            loader.setController(this);

            // Load the scene
            thisStage.setScene(new Scene(loader.load()));

            // Setup the window/stage
            thisStage.setTitle("Passing Controllers Example - Layout2");

        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * Show the stage that was loaded in the constructor
     */
    public void showStage() {
        thisStage.showAndWait();
    }

    @FXML
    private void initialize() {

        // Set the label to whatever the text entered on Layout1 is
        lblFromController1.setText(controller1.getEnteredText());

        // Set the action for the button
        btnSetLayout1Text.setOnAction(event -> setTextOnLayout1());
    }

    /**
     * Calls the "setTextFromController2()" method on the first controller to update its Label
     */
    private void setTextOnLayout1() {
        controller1.setTextFromController2(txtToFirstController.getText());
    }

}

Layout1.fxml:

<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.VBox?>
<AnchorPane xmlns="http://javafx.com/javafx/9.0.1" xmlns:fx="http://javafx.com/fxml/1">
    <VBox alignment="CENTER" spacing="10.0">
        <padding>
            <Insets bottom="10.0" left="10.0" right="10.0" top="10.0"/>
        </padding>
        <Label style="-fx-font-weight: bold;" text="This is Layout1!"/>
        <HBox alignment="CENTER_LEFT" spacing="10.0">
            <Label text="Enter Text:"/>
            <TextField fx:id="txtToSecondController"/>
            <Button fx:id="btnOpenLayout2" mnemonicParsing="false" text="Open Layout2"/>
        </HBox>
        <VBox alignment="CENTER">
            <Label text="Text From Controller2:"/>
            <Label fx:id="lblFromController2" text="Nothing Yet!"/>
        </VBox>
    </VBox>
</AnchorPane>

Layout2.fxml:

<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.VBox?>
<AnchorPane xmlns="http://javafx.com/javafx/9.0.1" xmlns:fx="http://javafx.com/fxml/1">
    <VBox alignment="CENTER" spacing="10.0">
        <padding>
            <Insets bottom="10.0" left="10.0" right="10.0" top="10.0"/>
        </padding>
        <Label style="-fx-font-weight: bold;" text="Welcome to Layout 2!"/>
        <VBox alignment="CENTER">
            <Label text="Text From Controller1:"/>
            <Label fx:id="lblFromController1" text="Nothing Yet!"/>
        </VBox>
        <HBox alignment="CENTER_LEFT" spacing="10.0">
            <Label text="Enter Text:"/>
            <TextField fx:id="txtToFirstController"/>
            <Button fx:id="btnSetLayout1Text" mnemonicParsing="false" text="Set Text on Layout1"/>
        </HBox>
    </VBox>
</AnchorPane>
189
задан mwigdahl 24 March 2009 в 20:47
поделиться

10 ответов

Я вижу две возможных ситуации здесь. Во-первых, Вы хотите знать, существует ли стандарт SQL для этого, которое можно использовать в целом независимо от базы данных. Нет, нет. Во-вторых, Вы хотите знать относительно определенного продукта DBMS. Тогда необходимо определить его. Но я предполагаю, что наиболее вероятный ответ - то, что Вы возвратите что-то как "a.id, b.id", так как это - то, как необходимо было бы определить столбцы в SQL-выражении. И самый легкий способ узнать, каково значение по умолчанию, состоит в том, чтобы только отправить такой запрос и видеть то, что Вы возвращаете. Если Вы хотите определить, какой префикс прибывает перед точкой можно использовать "ВЫБОР * ОТ AS my_alias", например.

35
ответ дан dkretz 4 November 2019 в 15:18
поделиться

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

относительно того, как сделать Ваш запрос, не уверенный в mysql, но в sqlserver, Вы могли выбрать имена столбцов из syscolumns и динамично создать избранный пункт.

0
ответ дан Kozyarchuk 4 November 2019 в 15:18
поделиться

Существует два способа, которыми я могу думать, чтобы заставить это произойти допускающим повторное использование способом. Нужно переименовать все Ваши столбцы с префиксом для таблицы, из которой они произошли. Я много раз видел это, но мне действительно не нравится он. Я нахожу, что это избыточно, причины большой ввод, и можно всегда использовать псевдонимы, когда необходимо покрыть случай возникающего имени столбца.

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

Наконец, я не ясен, почему необходимо знать, из которого прибыла таблица каждый из столбцов. Это имеет значение? В конечном счете то, что имеет значение, является данными, которые они содержат. Произошел ли UserID из таблицы User, или таблица UserQuestion действительно не имеет значения. Имеет значение, конечно, когда необходимо обновить его, но в той точке необходимо уже знать, что схема достаточно хорошо определяет это.

1
ответ дан RedFilter 4 November 2019 в 15:18
поделиться

Нет никакого стандарта SQL для этого.

Однако С генерацией кода (или по требованию поскольку таблицы составлены или изменены или во времени выполнения), можно сделать это довольно легко:

CREATE TABLE [dbo].[stackoverflow_329931_a](
    [id] [int] IDENTITY(1,1) NOT NULL,
    [col2] [nchar](10) NULL,
    [col3] [nchar](10) NULL,
    [col4] [nchar](10) NULL,
 CONSTRAINT [PK_stackoverflow_329931_a] PRIMARY KEY CLUSTERED 
(
    [id] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]

CREATE TABLE [dbo].[stackoverflow_329931_b](
    [id] [int] IDENTITY(1,1) NOT NULL,
    [col2] [nchar](10) NULL,
    [col3] [nchar](10) NULL,
    [col4] [nchar](10) NULL,
 CONSTRAINT [PK_stackoverflow_329931_b] PRIMARY KEY CLUSTERED 
(
    [id] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]

DECLARE @table1_name AS varchar(255)
DECLARE @table1_prefix AS varchar(255)
DECLARE @table2_name AS varchar(255)
DECLARE @table2_prefix AS varchar(255)
DECLARE @join_condition AS varchar(255)
SET @table1_name = 'stackoverflow_329931_a'
SET @table1_prefix = 'a_'
SET @table2_name = 'stackoverflow_329931_b'
SET @table2_prefix = 'b_'
SET @join_condition = 'a.[id] = b.[id]'

DECLARE @CRLF AS varchar(2)
SET @CRLF = CHAR(13) + CHAR(10)

DECLARE @a_columnlist AS varchar(MAX)
DECLARE @b_columnlist AS varchar(MAX)
DECLARE @sql AS varchar(MAX)

SELECT @a_columnlist = COALESCE(@a_columnlist + @CRLF + ',', '') + 'a.[' + COLUMN_NAME + '] AS [' + @table1_prefix + COLUMN_NAME + ']'
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = @table1_name
ORDER BY ORDINAL_POSITION

SELECT @b_columnlist = COALESCE(@b_columnlist + @CRLF + ',', '') + 'b.[' + COLUMN_NAME + '] AS [' + @table2_prefix + COLUMN_NAME + ']'
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = @table2_name
ORDER BY ORDINAL_POSITION

SET @sql = 'SELECT ' + @a_columnlist + '
,' + @b_columnlist + '
FROM [' + @table1_name + '] AS a
INNER JOIN [' + @table2_name + '] AS b
ON (' + @join_condition + ')'

PRINT @sql
-- EXEC (@sql)
2
ответ дан Cade Roux 4 November 2019 в 15:18
поделиться

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

5
ответ дан dkretz 4 November 2019 в 15:18
поделиться

Я натурален из той же лодки как OP - у меня есть десятки полей от 3 различных таблиц, к которым я присоединяюсь, некоторые из которых имеют то же имя (т.е. идентификатор, имя, и т.д.). Я не хочу перечислять каждое поле, таким образом, мое решение состояло в том, чтобы исказить те поля, которые совместно использовали имя, и используйте выбор * для тех, которые имеют уникальное имя.

, Например:

таблица a: идентификатор, имя, field1, field2...

таблица b: идентификатор, имя, field3, field4...

выбор a.id как ПОМОЩЬ, a.name как aName, a. *, b.id столь же предложенный, b.name как bName, b. *.....

При доступе к результатам I нас искаженные названия этих полей и игнорируют "исходные" имена.

, Возможно, не лучшее решение, но это работает на меня...., я - mysql

использования
6
ответ дан 4 November 2019 в 15:18
поделиться

Единственная база данных я знаю это, делает это - SQLite, в зависимости от настроек, которые Вы настраиваете с PRAGMA full_column_names и PRAGMA short_column_names. См. http://www.sqlite.org/pragma.html

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

Это - хороший пример того, почему это - плохая практика для использования SELECT * - потому что в конечном счете у Вас будет потребность вывести все имена столбцов так или иначе.

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

12
ответ дан Community 4 November 2019 в 15:18
поделиться

Или Вы могли использовать Красный SQL Логического элемента, Осуществляют рефакторинг или Подсказка SQL, которая разворачивает Ваш ВЫБОР * в списки столбцов щелчком кнопки

Tab так в Вашем случае, если Вы вводите в ВЫБОРЕ * ОТ СОЕДИНЕНИЯ B... Пойдите до конца *, кнопка Tab, вуаля! Вы будете видеть ВЫБОР Column1, Column2...., B.column1, B.column2 ОТ B

СОЕДИНЕНИЯ, Это не свободно хотя

1
ответ дан jerryhung 4 November 2019 в 15:18
поделиться

Есть прямой ответ на ваш вопрос для тех, кто использует MySQL C-API.

Учитывая SQL:

  SELECT a.*, b.*, c.* FROM table_a a JOIN table_b b USING (x) JOIN table_c c USING (y)

Результаты mysql_stmt_result_metadata () дают определение ваших полей из вашего подготовленного SQL-запроса в структуру MYSQL_FIELD []. Каждое поле содержит следующие данные:

  char *name;                 /* Name of column (may be the alias) */
  char *org_name;             /* Original column name, if an alias */
  char *table;                /* Table of column if column was a field */
  char *org_table;            /* Org table name, if table was an alias */
  char *db;                   /* Database for table */
  char *catalog;              /* Catalog for table */
  char *def;                  /* Default value (set by mysql_list_fields) */
  unsigned long length;       /* Width of column (create length) */
  unsigned long max_length;   /* Max width for selected set */
  unsigned int name_length;
  unsigned int org_name_length;
  unsigned int table_length;
  unsigned int org_table_length;
  unsigned int db_length;
  unsigned int catalog_length;
  unsigned int def_length;
  unsigned int flags;         /* Div flags */
  unsigned int decimals;      /* Number of decimals in field */
  unsigned int charsetnr;     /* Character set */
  enum enum_field_types type; /* Type of field. See mysql_com.h for types */

Обратите внимание на поля: catalog, table, org_name

Теперь вы знаете, какие поля в вашем SQL принадлежат какой схеме (также известной как каталог) и таблице. Этого достаточно для общей идентификации каждого поля из многотабличного sql-запроса без необходимости использования псевдонима.

Реальный продукт SqlYOG использует эти точные данные в такой усадьбе, что они могут независимо обновлять каждую таблицу соединения нескольких таблиц, когда присутствуют поля PK.

0
ответ дан 23 November 2019 в 05:40
поделиться

Если вас беспокоит изменение схемы, это может сработать для вас: 1. Выполните запрос «DESCRIBE table» для всех задействованных таблиц. 2. Используйте возвращенные имена полей для динамического создания строки имен столбцов с префиксом выбранного псевдонима.

0
ответ дан 23 November 2019 в 05:40
поделиться
Другие вопросы по тегам:

Похожие вопросы: