0

提供された郵便番号とデータベースに格納された郵便番号、および重量の側面に基づいて、一致するレコードを見つける SQL ステートメントを作成しようとしています。

データベース内の郵便番号は、1 文字または 2 文字、つまり B、BA ... です。

現在 - SQL ステートメントに渡される値には、常にクライアントの郵便番号の最初の 2 文字が含まれます。どうすれば一致するものを見つけることができますか? 郵便番号 B1 があるとします。これは、データベース内の単一の B と重量の側面のみに一致します。これで問題ありません。

これは私の現在の SQL ステートメントです。これは、特定の重量を超える送料無料の係数もとっています。

SELECT `s`.*,
IF (
    '{$weight}' > (
        SELECT MAX(`weight_from`)
        FROM `shipping`
        WHERE UPPER(SUBSTRING(`post_code`, 1, 2)) = 'B1'
    ),
    (
        SELECT `cost`
        FROM `shipping`
        WHERE UPPER(SUBSTRING(`post_code`, 1, 2)) = 'B1'
        ORDER BY `weight_from` DESC
        LIMIT 0, 1
    ),
    `s`.`cost`
) AS `cost`
FROM `shipping` `s`
WHERE UPPER(SUBSTRING(`s`.`post_code`, 1, 2)) = 'B1'
AND 
(
    (
        '{$weight}' > (
            SELECT MAX(`weight_from`)
            FROM `shipping`
            WHERE UPPER(SUBSTRING(`post_code`, 1, 2)) = 'B1'
        )
    )
    OR 
    ('{$weight}' BETWEEN `s`.`weight_from` AND `s`.`weight_to`)
)
LIMIT 0, 1

ただし、上記では、ハードコードされた文字数を 2 に設定して SUBSTRING() 関数を使用しています。これは、提供された郵便番号 (この場合は B1) に一致する文字数のみに一致させるために、実際に助けが必要な場所です。

マーカス - 助けてくれてありがとう - 素晴らしい例 - 私のコードは次のようになります:

まず、次のステートメントを実行して、正しい郵便番号を取得しました。

(
    SELECT `post_code`
    FROM `shipping`
    WHERE `post_code` = 'B1'
)
UNION
(
    SELECT `post_code`
    FROM `shipping`
    WHERE `post_code` = SUBSTRING('B1', 1, 1)
)
ORDER BY `post_code` DESC
LIMIT 0, 1

次に、'post_code' インデックスに割り当てられた戻り値に基づいて、次の 2 番目のステートメントを実行します。

$post_code = $result['post_code'];

SELECT `s`.*,
IF (
    '1000' > (
        SELECT MAX(`weight_from`)
        FROM `shipping`
        WHERE `post_code` = '{$post_code}'  
    ),
    (
        SELECT `cost`
        FROM `shipping`
        WHERE `post_code` = '{$post_code}'
        ORDER BY `weight_from` DESC
        LIMIT 0, 1
    ),
    `s`.`cost`
) AS `cost`
FROM `shipping` `s`
WHERE `s`.`post_code` = '{$post_code}'
AND 
(
    (
        '1000' > (
            SELECT MAX(`weight_from`)
            FROM `shipping`
            WHERE `post_code` = '{$post_code}'
            ORDER BY LENGTH(`post_code`) DESC
        )
    )
    OR 
    ('1000' BETWEEN `s`.`weight_from` AND `s`.`weight_to`)
)
LIMIT 0, 1
4

1 に答える 1

3

次のクエリは、shipping テーブルの post_code が、渡された post_code の先頭と一致するすべての結果を取得し、最も明示的なものから最も明示的でないものへと並べ替え、最も明示的なものを返します。

SELECT *
FROM shipping
WHERE post_code = SUBSTRING('B1', 1, LENGTH(post_code))
ORDER BY LENGTH(post_code) DESC
LIMIT 1

アップデート

このクエリは柔軟ですが、インデックスを利用できないため、あまり高速ではありません。配送テーブルが大きく、最大 2 文字しか渡さない場合は、2 つの別々の呼び出しを行った方が速い場合があります。

まず、最も明示的な呼び出しを試します。

SELECT *
FROM shipping
WHERE post_code = 'B1'

結果が返されない場合は、1 文字で検索します。

SELECT *
FROM shipping
WHERE post_code = SUBSTRING('B1', 1, 1)

もちろん、単一の呼び出しで行う必要がある場合は、これらを UNION と組み合わせることができます。

SELECT * FROM
((SELECT *
FROM shipping
WHERE post_code = 'B1')
UNION
(SELECT *
FROM shipping
WHERE post_code = SUBSTRING('B1', 1, 1))) a
ORDER BY post_code DESC
LIMIT 1
于 2012-01-26T17:57:53.970 に答える