Код SQL в классах Java

Сначала вы перебираете строки в кадре данных:

for index, row in yourdf.iterrows():

Затем для каждой строки в кадре данных вы сравниваете два значения, которые хотите сравнить:

if row['First_name1'] == row['first_name2']:
    # Create the new column and set its value to first_name
    row['new_column'] = first_name
else:
    # Set each column to the value you want
    row['first_name'] = first_name1
    row['first_name2'] = first_name1
11
задан Jonathan Leffler 17 July 2015 в 05:44
поделиться

16 ответов

Я сохранил SQL как строки внутри класса Java, так и как отдельные файлы, загруженные во время выполнения. Я очень предпочел последнее по двум причинам. Во-первых, код более читабелен с большим отрывом. Во-вторых, проще тестировать SQL изолированно, если вы храните его в отдельном файле. Кроме того, было легче найти кого-то лучше меня в SQL, чтобы он помогал мне с моими запросами, когда они находились в отдельных файлах.

8
ответ дан 3 December 2019 в 07:39
поделиться

What you need here is SQLJ which is a SQL Java-Preprocessor. Sadly, apparently it never took off, although I have seen some IBM and Oracle implementations. But they are quite outdated.

If I were you and had lots and lots of queries on the system, I would stored them in a separate file and load them at runtime.

0
ответ дан 3 December 2019 в 07:39
поделиться

From my experience it is better to leave the SQL statements in the code not separating them makes things more maintainable (like annotations vs. config files), but now I have a debate with a team member about it.

0
ответ дан 3 December 2019 в 07:39
поделиться

I would imagine that storing a query in an external file, and then have the application read it when needed presents a HUGE security hole.

What happens if an evil mastermind has access to that file and changes your query?

For example changes

 select a from A_TABLE;

TO

 drop table A_TABLE;

OR

 update T_ACCOUNT set amount = 1000000

Plus, it adds the complexity of having to mantain two things: Java Code, and SQL query files.

EDIT: Yes, you can change your queries without recompiling your app. I don't see the big deal there. You could recompile classes that hold/create sqlQueries only, if the project is too big. Besides, if documentation is poor, maybe you'd end up changing the incorrect file, and that will turn into an enormous silent bug. No exception or error codes will be thrown, and when you realize what you've done, it may be too late.

A different approach would be to have some sort of SQLQueryFactory, well documented, and with methods that return a SQL query that you want to use.

For example

public String findCheapest (String tableName){

      //returns query.
}
0
ответ дан 3 December 2019 в 07:39
поделиться

We had a project where we used the exact approach you are, except we externalized each query to a separate text file. Each file was read in (once) using Spring's ResourceLoader framework and the application worked via an interface like this:

public interface SqlResourceLoader {
    String loadSql(String resourcePath);
}

A distinct advantage with this was that having the SQL in an un-escaped format allowed for easier debugging -- just read the file into a query tool. Once you have more than a few queries of moderate complexity, dealing with un/escaping to/from the code while testing & debugging (particularly for tuning) it was invaluable.

We also had to support a couple of different databases, so it allowed for swapping the platform more easily.

0
ответ дан 3 December 2019 в 07:39
поделиться

Based on the issue as you explained it, there is no real choice here except to keep it in the code, and get rid of the /n characters everywhere. This is the only thing that you mentioned as affecting readability and they are absolutely unnecessary.

Unless you have other issues with it being in the code your problem is easily solved.

0
ответ дан 3 December 2019 в 07:39
поделиться

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

0
ответ дан 3 December 2019 в 07:39
поделиться

Один из вариантов - использовать iBatis . Он довольно легкий по сравнению с полноценной ORM, такой как Hibernate, но предоставляет средства для хранения ваших SQL-запросов вне ваших файлов .java

0
ответ дан 3 December 2019 в 07:39
поделиться

Why not use Stored Procedures instead of hard coding queries? Stored Procs will increase maintainability and provide more security for things like SQL Interjection Attacks.

0
ответ дан 3 December 2019 в 07:39
поделиться

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

Например, используя Groovy, запрос, который вы указали выше, будет просто:

class Queries
    private static final String PRODUCT_IDS_PARAM = ":productIds"

    public static final String FIND_ALL_BY_CHEAPEST_AND_PRODUCT_IDS = 
    """    FROM PRODUCT_SKU T 
        JOIN 
        ( 
            SELECT S.PRODUCT_ID, 
                   MIN(S.ID) as minimum_id_for_price 
              FROM PRODUCT_SKU S 
             WHERE S.PRODUCT_ID IN ($PRODUCT_IDS_PARAM) 
          GROUP BY S.PRODUCT_ID, S.SALE_PRICE 
        ) FI ON (FI.PRODUCT_ID = T.PRODUCT_ID AND FI.minimum_id_for_price = T.ID) 
        JOIN 
        ( 
            SELECT S.PRODUCT_ID, 
                   MIN(S.SALE_PRICE) as minimum_price_for_product 
              FROM PRODUCT_SKU S 
             WHERE S.PRODUCT_ID IN ($PRODUCT_IDS_PARAM) 
          GROUP BY S.PRODUCT_ID 
        ) FP ON (FP.PRODUCT_ID = T.PRODUCT_ID AND FP.minimum_price_for_product = T.sale_price) 
    WHERE T.PRODUCT_ID IN ($PRODUCT_IDS_PARAM) """

Вы можете получить доступ к этому классу из Java код, точно так же, как если бы он был определен в Java, например

String query = QueryFactory.FIND_ALL_BY_CHEAPEST_AND_PRODUCT_IDS;

Я признаю, что добавление Groovy в ваш путь к классам только для того, чтобы ваши SQL-запросы выглядели лучше, - это своего рода решение "кувалдой, чтобы сломать орех", но если вы используете Spring, велика вероятность, что вы уже используете Groovy на своем пути к классам.

Кроме того, есть ' Вероятно, есть много других мест в вашем проекте, где вы могли бы использовать Groovy (вместо Java) для улучшения вашего кода (особенно теперь, когда Groovy принадлежит Spring). Примеры включают написание тестовых примеров или замену Java-бинов на Groovy-бины.

2
ответ дан 3 December 2019 в 07:39
поделиться

I've run into this as well, currently for the same reason - a project based on spring jdbc. My experience is that while it's not great to have the logic in the sql itself, there's really no better place for it , and putting in the application code is slower than having the db do it and not necessarily any clearer.

Biggest pitfalls I've seen with this is where the sql starts to proliferate all over the project, with multiple variations. "Get A, B, C from FOO". "Get A, B, C, E from Foo", etc.etc. This sort of proliferation is especially likely as the project hits a certain critical mass - it may not seem like an issue with 10 queries, but when there's 500 queries scattered throughout the project it becomes much harder to figure out if you've already done something. Abstracting out the basic CRUD operations puts you way ahead of the game here.

Best solution, AFAIK, is to be rigorously consistent with the coded SQL - commented, tested, and in a consistent place. Our project has 50-line uncommented sql queries. What do they mean? Who knows?

As for queries in external files, I don't see what this buys - You're still just as reliant on the SQL, and with the exception of the (questionable) aesthetic improvement of keeping the sql out of the classes, your classes are still just as reliant on the sql -.e.g you generally separate resources to get the flexibility to plug-in replacement resources, but you couldn't plug in replacement sql queries as that'd change the semantic meaning of the class or not work at all. So it's an illusory code-cleanliness.

5
ответ дан 3 December 2019 в 07:39
поделиться

Мы храним весь наш SQL в классе как набор статических конечных строк. Для удобства чтения мы разложили его на несколько строк, объединенных с помощью +. Кроме того, я не уверен, нужно ли вам избегать чего-либо - «Строки» заключаются в одинарные кавычки в sql.

0
ответ дан 3 December 2019 в 07:39
поделиться

Since you already use Spring why not put the SQL in the Spring config file and DI it into the DAO class? That is a simple way to externalize the SQL string.

HTH Tom

0
ответ дан 3 December 2019 в 07:39
поделиться

У меня есть небольшая программа, которая обращается к буферу обмена и экранирует / отменяет экранирование обычного текста с помощью строковых литералов Java.

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

Ctrl+C, Click jar, Ctrl+V

Либо когда я хочу запустить свой «код» в инструмент SQL, либо наоборот.

Итак, у меня обычно есть что-то вроде этого:

String query = 
    "SELECT a.fieldOne, b.fieldTwo \n"+
    "FROM  TABLE_A a, TABLE b \n"+ 
    "... etc. etc. etc";


logger.info("Executing  " + query  );

PreparedStatement pstmt = connection.prepareStatement( query );
....etc.

Что преобразуется в:

    SELECT a.fieldOne, b.fieldTwo 
    FROM  TABLE_A a, TABLE b
    ... etc. etc. etc

Либо потому, что в некоторых проектах я не могу создавать отдельные файлы, либо потому, что я параноик и чувствую, что некоторые биты будут вставлены / удалены при чтении из внешний файл (обычно невидимый \ n, который превращает

select a,b,c 
from 

в

select a,b,cfrom 

Идея IntelliJ делает то же самое для вас автоматически, но только от простого к коду.

Вот старая версия, которую я восстановил. Она немного сломана и не обрабатывает ?.

Дайте мне знать, если кто-нибудь улучшит его.

import java.awt.Toolkit;
import java.awt.datatransfer.Clipboard;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.ClipboardOwner;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.StringSelection;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.io.IOException;

/**
 * Transforms a plain string from the clipboard into a Java 
 * String literal and viceversa.
 * @author <a href="http://stackoverflow.com/users/20654/oscar-reyes">Oscar Reyes</a>
 */
public class ClipUtil{

    public static void main( String [] args ) 
                                throws UnsupportedFlavorException,
                                                     IOException {

        // Get clipboard
        Toolkit toolkit = Toolkit.getDefaultToolkit();
        Clipboard clipboard = toolkit.getSystemClipboard();

        // get current content.
        Transferable transferable = clipboard.getContents( new Object() ); 
        String s = ( String ) transferable.getTransferData( 
                                                DataFlavor.stringFlavor );

        // process the content
        String result = process( s );

        // set the result
        StringSelection ss = new StringSelection( result );
        clipboard.setContents( ss, ss );

    }
    /**
     * Transforms the given string into a Java string literal 
     * if it represents plain text and viceversa. 
     */
    private static String process( String  s ){
        if( s.matches( "(?s)^\\s*\\\".*\\\"\\s*;$" ) ) {
            return    s.replaceAll("\\\\n\\\"\\s*[+]\n\\s*\\\"","\n")
                       .replaceAll("^\\s*\\\"","")
                       .replaceAll("\\\"\\s*;$","");
        }else{
            return     s.replaceAll("\n","\\\\n\\\" +\n \\\" ")
                        .replaceAll("^"," \\\"")
                        .replaceAll("$"," \\\";");
        }
    }
}
0
ответ дан 3 December 2019 в 07:39
поделиться

Мы используем хранимые процедуры. Для нас это хорошо, потому что мы используем Oracle Fine Grain Access. Это позволяет нам ограничить просмотр пользователем определенного отчета или результатов поиска, ограничив их доступ к соответствующей процедуре.

1
ответ дан 3 December 2019 в 07:39
поделиться

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

Для Java я использую класс Properties, который представляет SQL в файле .properties, что позволяет передавать SQL запросы вокруг, если вы хотите повторно использовать запросы, а не читать файл несколько раз.

0
ответ дан 3 December 2019 в 07:39
поделиться
Другие вопросы по тегам:

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