MW211 EXIT

devlog
MSSQL/FOR XML PATHを復習
2022年05月28日
複数行を横一列にする方法として、MSSQLでは「FOR XML PATH」を用いる。
その意味をもう一度復習

「FOR XML PATH」をつけると、XML形式として横一列に表示ができる。
┌──────────────────────────────────────┐
│WITH [表] AS (                                                              │
│         SELECT * FROM (VALUES ('A'),                                       │
│                               ('B'),                                       │
│                               ('C')) AS [表]([列])                         │
│     )                                                                      │
│SELECT [列]                                                                 │
│    FROM [表]                                                               │
│    FOR XML PATH ('');                                                      │
│--→「<列>A</列><列>B</列><列>C</列>」                                      │
└──────────────────────────────────────┘
通常は列名でタグが付いてくる。

これを、列名[data()]にすると、スペース区切りにすることができる
┌──────────────────────────────────────┐
│WITH [表] AS (                                                              │
│         SELECT * FROM (VALUES ('A'),                                       │
│                               ('B'),                                       │
│                               ('C')) AS [表]([列])                         │
│     )                                                                      │
│SELECT [列] AS [data()]                                                     │
│    FROM [表]                                                               │
│    FOR XML PATH ('');                                                      │
│--→「A B C」                                                               │
└──────────────────────────────────────┘
内側だけにスペースが付くので便利。
このスペースを区切り文字に置換すればよいわけだ。

では列名をなくしてしまえばどうだろう。
どのようなやり方でもよいがAS句で列名を指定しなければないけない形にもっていく。
(以下の場合は人畜無害な空文字を付加する形をとってみた)
┌──────────────────────────────────────┐
│WITH [表] AS (                                                              │
│         SELECT * FROM (VALUES ('A'),                                       │
│                               ('B'),                                       │
│                               ('C')) AS [表]([列])                         │
│     )                                                                      │
│SELECT [列] + ''                                                            │
│    FROM [表]                                                               │
│    FOR XML PATH ('');                                                      │
│--→「ABC」                                                                 │
└──────────────────────────────────────┘
これで列名によるタグがなくなるが、今度は区切りがまったくなくなってしまう。

ということで、自前で区切り文字をあらかじめつけたのが以下。
┌──────────────────────────────────────┐
│WITH [表] AS (                                                              │
│         SELECT * FROM (VALUES ('A'),                                       │
│                               ('B'),                                       │
│                               ('C')) AS [表]([列])                         │
│     )                                                                      │
│SELECT [列] + ','                                                           │
│    FROM [表]                                                               │
│    FOR XML PATH ('');                                                      │
│--→「A,B,C,」                                                              │
└──────────────────────────────────────┘
好きな区切り文字を指定できるが、外側にもついてしまうのが難点。


ちなみに「',' + [列]」と逆にすると、「,A,B,C」になる。
┌──────────────────────────────────────┐
│WITH [表] AS (                                                              │
│         SELECT * FROM (VALUES ('A'),                                       │
│                               ('B'),                                       │
│                               ('C')) AS [表]([列])                         │
│     )                                                                      │
│SELECT STUFF((SELECT ',' + [列]                                             │
│                  FROM [表]                                                 │
│                  FOR XML PATH ('')), 1, 1, '');                            │
│--→「A,B,C」                                                               │
└──────────────────────────────────────┘
そこでSTUFF関数と組み合わせればなんとなくいけるかも。

列名[data()]のやり方だとデータ中に半角スペースが混じっていると
破綻してしまうのだが、以下のような感じで
使われないであろう文字を区切り文字にして回避することができてしまう。
┌──────────────────────────────────────┐
│WITH [表] AS (                                                              │
│         SELECT * FROM (VALUES ('A X'),                                     │
│                               ('B Y'),                                     │
│                               ('C Z')) AS [表]([列])                       │
│     )                                                                      │
│SELECT REPLACE(STUFF((SELECT '\n' + [列]                                    │
│                          FROM [表]                                         │
│                          FOR XML PATH ('')), 1, 2, ''), '\n', CHAR(10));   │
│--→「A X                                                                   │
│      B Y                                                                   │
│      C Z」                                                                 │
└──────────────────────────────────────┘
分類:MSSQL
MSSQL/JOINによるUPDATEで複数候補
2022年05月27日
他テーブルをJOINしてUPDATEする場合、複数行になったらどうなるのか?
┌──────────────────────────────────────┐
│GO                                                                          │
│    DECLARE @テストD table (                                               │
│        [列]    [nvarchar](16)  NULL                                        │
│    );                                                                      │
│    INSERT INTO @テストD VALUES (NULL);                                    │
│    UPDATE [出力D]                                                         │
│        SET [列] = [入力D].[列]                                            │
│        FROM @テストD AS [出力D]                                          │
│            CROSS JOIN (                                                    │
│                SELECT *                                                    │
│                    FROM (                                                  │
│                        VALUES ('A'),                                       │
│                               ('B'),                                       │
│                               ('C')                                        │
│                    ) AS [入力D]([列])                                     │
│            ) AS [入力D];                                                  │
│    SELECT * FROM @テストD;                                                │
│GO                                                                          │
│--→「A」に更新された                                                       │
└──────────────────────────────────────┘
最初のレコードが優先される。

でも、最初ってなんだよ?問題が発生する恐れがあるので、
あまり使わない方がよいだろう。
ひとまず二重キーエラーとかにならないので、対策は軽くてよいということで。
分類:MSSQL
PHP/自前のgetCsv()
2022年05月14日
┌──────────────────────────────────────┐
│function getCsv($rows) {                                                    │
│    if (count($rows) == 0) {                                                │
│        return NULL;                                                        │
│    }                                                                       │
│    $return = [];                                                           │
│    $i = 0;                                                                 │
│    $return[] = implode(',', array_keys($rows[$i]));                        │
│    // 二件目以降読込                                                       │
│    do {                                                                    │
│        // CSV補正                                                          │
│        foreach ($rows[$i] as &$column) {                                   │
│            // 「"」を「""」に変換                                          │
│            if (preg_match('/"/', $column)) {                               │
│                $column = preg_replace('/"/', '""', $column);               │
│            }                                                               │
│            // 「"~"」で囲う                                               │
│            if ((preg_match('/"/' , $column))                               │
│             || (preg_match('/,/' , $column))                               │
│             || (preg_match('/\n/', $column)))                              │
│            {                                                               │
│                $column = '"' . $column . '"';                              │
│            }                                                               │
│        }                                                                   │
│        unset($column);                                                     │
│        //                                                                  │
│        $return[] = implode(',', $rows[$i]);                                │
│        $i++;                                                               │
│    } while ($i < count($rows));                                            │
│    return implode("\r\n", $return) . "\r\n";                               │
│}                                                                           │
└──────────────────────────────────────┘
分類:PHP
jQuery/データのエクスポート
2022年05月13日
以下のような感じで。

【jQuery(JavaScript)】
┌──────────────────────────────────────┐
│$(':button').on('click', function() {                                       │
│    $.ajax({                                                                │
│            url         :URLを指定,                                         │
│            type        :'POST',                                            │
│            data        :{},                                                │
│            dataType    :'text',                                            │
│            timeout     :30000                                              │
│        })                                                                  │
│        .done(function(data, status, xhr) {                                 │
│            if (data) {                                                     │
│                const bom = new Uint8Array([0xEF, 0xBB, 0xBF]);             │
│                const blob = new Blob([bom, data], {'type':'text/csv'});    │
│                $('<a></a>', {                                              │
│                    'href'      :window.URL.createObjectURL(blob),          │
│                    'download'  :'エクスポート.csv',                        │
│                    'target'    :'_blank'                                   │
│                })[0].click();                                              │
│            } else {                                                        │
│                alert('エラー');                                            │
│            }                                                               │
│        })                                                                  │
│        .fail(function(xhr, status, error) {                                │
│            alert('エラー');                                                │
│        });                                                                 │
└──────────────────────────────────────┘
  API(のURL)を指定して、CSVデータを返してもらう。
  そして、それに先頭BOMをつけて、UTF-8形式でダウンロードする形にする。

【PHP】
┌──────────────────────────────────────┐
│echo '1,2,3';                                                               │
└──────────────────────────────────────┘
  API側では、CSVデータを返す。
分類:jQuery
前へ 1 次へ