AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • Início
  • system&network
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • Início
  • system&network
    • Recentes
    • Highest score
    • tags
  • Ubuntu
    • Recentes
    • Highest score
    • tags
  • Unix
    • Recentes
    • tags
  • DBA
    • Recentes
    • tags
  • Computer
    • Recentes
    • tags
  • Coding
    • Recentes
    • tags
Início / dba / Perguntas / 188420
Accepted
Andy K
Andy K
Asked: 2017-10-14 07:07:37 +0800 CST2017-10-14 07:07:37 +0800 CST 2017-10-14 07:07:37 +0800 CST

por que a última função no msaccess me permite ignorar o grupo?

  • 772

Eu tenho a seguinte consulta no msaccess

SELECT Trim([T13_RefSupplier_France_List].[Supplier_code]) AS Supplier_code,
       Trim([T13_RefSupplier_France_List].[Art]) AS Internal_reference,
       Trim([fp_rcli]) AS Supplier_reference,
       Last(Trim([ar_fami])) AS Family_code,
       Last(Trim([fp_upri])) AS Purchasing_unit,
       Last(Nz([fp_pcde],0)) AS Purchasing_price,
       Last(Supplier_currency_France.Recode) AS Purchasing_currency,
       Last("") AS Consigned,
       Last(0) AS Eco_order_qty,
       Last(CDbl(Nz(Nz([fp_cond],[ar_qcdi]),0))) AS Pack_order_qty,
       Last(IIf([fp_minc]=0,Nz([fp_cond],[ar_qcdi]),[fp_minc])) AS Min_order_qty,
       0 AS Min_order_value,
       0 AS Product_grossweight,
       0 AS Product_grosscube,
       Last(gpfprodu_France.fp_dela) AS Leadtime_days,
       Nz([Localisation_France].[Site],"Poitiers") AS Site,
       CDbl(Nz([Active],-1)) AS Supplier_active,
       Max(IIf([ar1_pdanz]=0,NULL,[ar1_pdanz])) AS Ref_price
FROM ((T13_RefSupplier_France_List
       LEFT JOIN ((gparticl_France
                   LEFT JOIN Localisation_France ON gparticl_France.ar_loco=Localisation_France.Localisation)
                  LEFT JOIN [*gpartic1_France] ON gparticl_France.ar_code=[*gpartic1_France].ar1_code) ON T13_RefSupplier_France_List.Art=gparticl_France.ar_code)
      LEFT JOIN ((gpfprodu_France
                  LEFT JOIN gpfourni_France ON gpfprodu_France.fp_four=gpfourni_France.fo_code)
                 LEFT JOIN Supplier_currency_France ON gpfourni_France.fo_monn=Supplier_currency_France.fo_monn) ON (T13_RefSupplier_France_List.Supplier_code=gpfprodu_France.fp_four)
      AND (T13_RefSupplier_France_List.Art=gpfprodu_France.fp_arti))
LEFT JOIN T13_RefSupplier_France_SupplierActive ON (T13_RefSupplier_France_List.Art=T13_RefSupplier_France_SupplierActive.Art)
AND (T13_RefSupplier_France_List.Supplier_code=T13_RefSupplier_France_SupplierActive.Supplier_code)
GROUP BY Trim([T13_RefSupplier_France_List].[Supplier_code]),
         Trim([T13_RefSupplier_France_List].[Art]),
         Trim([fp_rcli]),
         Nz([Localisation_France].[Site],"Poitiers"),
         CDbl(Nz([Active],-1))
HAVING (((Trim(T13_RefSupplier_France_List.Supplier_code))<>"FG0002")
        AND ((Trim(T13_RefSupplier_France_List.Art))<>"A60101000000000"));

Eu posso fazer uma GROUP BYsem usar a coluna que tem a LASTfunção mas quando eu removo a função LAST, tenho que adicionar todas as colunas na GROUP BY(veja abaixo).

SELECT Trim([T13_RefSupplier_France_List].[Supplier_code]) AS Supplier_code,
       Trim([T13_RefSupplier_France_List].[Art]) AS Internal_reference,
       Trim([fp_rcli]) AS Supplier_reference,
       Trim([ar_fami]) AS Family_code,
       Trim([fp_upri]) AS Purchasing_unit,
       Nz([fp_pcde],0) AS Purchasing_price,
       Supplier_currency_France.Recode AS Purchasing_currency,
       "" AS Consigned,
       0 AS Eco_order_qty,
       CDbl(Nz(Nz([fp_cond],[ar_qcdi]),0)) AS Pack_order_qty,
       IIf([fp_minc]=0,Nz([fp_cond],[ar_qcdi]),[fp_minc]) AS Min_order_qty,
       0 AS Min_order_value,
       0 AS Product_grossweight,
       0 AS Product_grosscube,
       gpfprodu_France.fp_dela AS Leadtime_days,
       Nz([Localisation_France].[Site],"Poitiers") AS Site,
       CDbl(Nz([Active],-1)) AS Supplier_active,
       Max(IIf([ar1_pdanz]=0,NULL,[ar1_pdanz])) AS Ref_price
FROM ((T13_RefSupplier_France_List
       LEFT JOIN ((gparticl_France
                   LEFT JOIN Localisation_France ON gparticl_France.ar_loco=Localisation_France.Localisation)
                  LEFT JOIN [*gpartic1_France] ON gparticl_France.ar_code=[*gpartic1_France].ar1_code) ON T13_RefSupplier_France_List.Art=gparticl_France.ar_code)
      LEFT JOIN ((gpfprodu_France
                  LEFT JOIN gpfourni_France ON gpfprodu_France.fp_four=gpfourni_France.fo_code)
                 LEFT JOIN Supplier_currency_France ON gpfourni_France.fo_monn=Supplier_currency_France.fo_monn) ON (T13_RefSupplier_France_List.Supplier_code=gpfprodu_France.fp_four)
      AND (T13_RefSupplier_France_List.Art=gpfprodu_France.fp_arti))
LEFT JOIN T13_RefSupplier_France_SupplierActive ON (T13_RefSupplier_France_List.Art=T13_RefSupplier_France_SupplierActive.Art)
AND (T13_RefSupplier_France_List.Supplier_code=T13_RefSupplier_France_SupplierActive.Supplier_code)
GROUP BY Trim([T13_RefSupplier_France_List].[Supplier_code]),
         Trim([T13_RefSupplier_France_List].[Art]),
         Trim([fp_rcli]),
         Nz([Localisation_France].[Site],"Poitiers"),
         Trim([ar_fami]),
         Trim([fp_upri]),
         Nz([fp_pcde],0),
         Supplier_currency_France.Recode,
         "",
         0,
         CDbl(Nz(Nz([fp_cond],[ar_qcdi]),0)),
         IIf([fp_minc]=0,Nz([fp_cond],[ar_qcdi]),[fp_minc]),
         0,
         0,
         0,
         gpfprodu_France.fp_dela,
         CDbl(Nz([Active],-1))
HAVING (((Trim(T13_RefSupplier_France_List.Supplier_code))<>"FG0002")
        AND ((Trim(T13_RefSupplier_France_List.Art))<>"A60101000000000")); 

As perguntas são duplas:

  • Qual é o comportamento da LASTfunção?
  • Digamos que eu queira transpor a LASTfunção para SQLServer: O que devo fazer?

Obrigado

sql-server ms-access
  • 2 2 respostas
  • 139 Views

2 respostas

  • Voted
  1. Paul White
    2017-10-15T00:56:04+08:002017-10-15T00:56:04+08:00

    Qual é o comportamento da LASTfunção?

    Da documentação :

    Essas funções retornam o valor de um campo especificado no primeiro ou último registro, respectivamente, do conjunto de resultados retornado por uma consulta. Se a consulta não incluir uma cláusula ORDER BY, os valores retornados por essas funções serão arbitrários, pois os registros geralmente não são retornados em uma ordem específica.

    Isso não diz nada sobre o comportamento de LASTquando uma GROUP BYcláusula está presente, mas ao testar parece que FIRSTe LASTretorna valores da linha encontrada primeiro ou por último em cada grupo.

    Sem uma ORDER BYcláusula, a linha escolhida (por grupo) por FIRSTe LASTé essencialmente arbitrária. O ponto importante é que os valores escolhidos pelas funções multiple FIRSTe virão da mesma linha .LAST

    Este último ponto significa que você não pode simplesmente substituir FIRSTou LASTpor MINou MAX(além das diferentes semânticas), porque o mínimo e o máximo geralmente não serão da mesma linha de origem.

    Digamos que eu queira transpor a LASTfunção para o SQL Server: O que devo fazer?

    É essencialmente impossível duplicar isso exatamente, pois o comportamento do Access não é definido com precisão; não é possível prever qual linha será escolhida como FIRSTou LASTem todos, exceto nos casos mais simples.

    Dito isso, se você puder melhorar a semântica da consulta para ter uma opção determinística para FIRSTou LASTlinha dentro de cada grupo, uma tradução geral seria numerar cada linha (crescente ou decrescente por grupo) e, em seguida, escolha valores da linha numerada 1.

    A numeração das linhas pode ser feita com ROW_NUMBER. Dentro da OVERcláusula, as GROUP BYcolunas vão na PARTITION BYseção, com ordenação determinística fornecida na ORDER BYseção. Você precisará escrever uma subconsulta ou usar uma expressão de tabela comum (CTE) para filtrar o número da linha para 1.

    Por exemplo:

    DECLARE @Table1 table
    (
        ID integer IDENTITY NOT NULL,
        GroupID integer NOT NULL,
        [Data] integer NOT NULL
    );
    
    INSERT @Table1
        (GroupID, [Data])
    VALUES
        (1, 3),
        (1, 2),
        (1, 1),
        (2, 6),
        (2, 5),
        (2, 4);
    
    -- FIRST (ordered by ID ASC within GroupID)
    WITH Numbered AS
    (
        SELECT
            T.GroupID,
            T.[Data],
            rn = ROW_NUMBER() OVER (
                    PARTITION BY T.GroupID
                    ORDER BY T.ID ASC)
        FROM @Table1 AS T
    )
    SELECT
        N.GroupID,
        N.[Data]
    FROM Numbered AS N
    WHERE
        N.rn = 1;
    
    -- LAST (ordered by ID DESC within GroupID)
    WITH Numbered AS
    (
        SELECT
            T.GroupID,
            T.[Data],
            rn = ROW_NUMBER() OVER (
                    PARTITION BY T.GroupID
                    ORDER BY T.ID DESC)
        FROM @Table1 AS T
    )
    SELECT
        N.GroupID,
        N.[Data]
    FROM Numbered AS N
    WHERE
        N.rn = 1;
    

    Demonstração:db<>fiddle

    No SQL Server 2012 ou posterior, isso também pode ser feito com as funções FIRST_VALUEe em LAST_VALUEjanela, mas o plano de execução pode ser menos eficiente. Além disso, essas funções em janela não são agregadas, portanto, você precisa escrever a expressão para que ela retorne o mesmo valor para cada linha por grupo e, em seguida, aplicar uma agregação arbitrária. Por exemplo (usando ordenação não determinística apenas para variedade):

    DECLARE @Table1 table
    (
        ID integer IDENTITY NOT NULL,
        GroupID integer NOT NULL,
        [Data] integer NOT NULL
    );
    
    INSERT @Table1
        (GroupID, [Data])
    VALUES
        (1, 3),
        (1, 2),
        (1, 1),
        (2, 6),
        (2, 5),
        (2, 4);
    
    WITH Windowed AS
    (
        SELECT
            T.GroupID,
            fv = FIRST_VALUE(T.[Data]) OVER (
                    PARTITION BY T.GroupID
                    ORDER BY T.GroupID
                    ROWS BETWEEN UNBOUNDED PRECEDING
                    AND UNBOUNDED FOLLOWING)
        FROM @Table1 AS T
    )
    SELECT
        W.GroupID,
        [Data] = MIN(W.fv)   -- arbitrary aggregate
    FROM Windowed AS W
    GROUP BY
        W.GroupID;
    
    WITH Windowed AS
    (
        SELECT
            T.GroupID,
            lv = LAST_VALUE(T.[Data]) OVER (
                    PARTITION BY T.GroupID
                    ORDER BY T.GroupID
                    ROWS BETWEEN UNBOUNDED PRECEDING
                    AND UNBOUNDED FOLLOWING)
        FROM @Table1 AS T
    )
    SELECT
        W.GroupID,
        [Data] = MAX(W.lv)   -- arbitrary aggregate
    FROM Windowed AS W
    GROUP BY
        W.GroupID;
    

    Demonstração:db<>fiddle

    Sua terceira opção é escrever um agregado definido pelo usuário (UDA) SQLCLR. Atualmente, não é possível garantir a ordenação determinística com eles, mas a implementação pode corresponder mais ao que o Access faz. Você precisaria ter cuidado para que todos os resultados UDA fossem calculados pelo mesmo operador, para garantir que os resultados de várias chamadas UDA venham da mesma linha de origem.

    • 5
  2. Best Answer
    RDFozz
    2017-10-14T13:32:35+08:002017-10-14T13:32:35+08:00

    RESUMO

    • Com GROUP BY, você só pode incluir as colunas na GROUP BYcláusula, constantes e valores agregados.
    • O SQL Server tem uma função de janela semelhante LAST_VALUE(), mas só existe no SQL Server 2012 ou posterior.

    EXPLICAÇÃO DETALHADA

    LAST()é o que chamamos de função agregada . As funções agregadas calculam um valor para todas as linhas em uma consulta (se não houver GROUP BY, ou para todas as linhas com os mesmos valores para as colunas na GROUP BYcláusula. No SQL Server (e, suponho, no Access), se você usar um função agregada em sua SELECTlista (a lista de colunas de dados a serem retornadas da consulta) em uma consulta sem GROUP BYcláusula, então tudo que está sendo retornado deve ser:

    • Valores que não dependem dos dados da sua tabela:
      • valores constantes como Consignedou Min_order_valueem sua consulta
      • os resultados de funções que não operam nos dados da tabela, como NOW()no Access ou GETDATE()no SQL Server
    • Os resultados de funções agregadas (geralmente operando em colunas das tabelas na consulta), como as LAST()funções de sua primeira consulta ou Max(IIf([ar1_pdanz]=0,NULL,[ar1_pdanz]))em ambas as consultas.

    Se você tiver uma GROUP BYcláusula, há uma adição ao acima: a SELECTlista também pode incluir as colunas (ou cálculos) listadas na GROUP BYcláusula. Geralmente, eles precisam aparecer exatamente da mesma forma nos dois lugares (por exemplo, se você GROUP BY SUBSTRING(field1,1,20), não pode ter apenas field1na SELECTlista).

    Quando você coloca Last(Trim([ar_fami]))em sua SELECTlista, você está basicamente dizendo ao Access: "Haverá vários valores para ar_famino meu grupo, mas eu realmente não me importo com quais são esses valores; apenas me dê o valor da última linha em que você acontece ver."

    Se você incluir Trim([ar_fami])na SELECTlista e no arquivo GROUP BY, estará informando ao Access que deseja ver cada valor exclusivo em sua saída e os subtotais/médias/qualquer coisa desses valores, juntamente com o restante das colunas no arquivo GROUP BY.

    Quando você tenta incluir Trim([ar_fami])na SELECTlista, mas não no GROUP BY, o Access fica confuso: você pode ter vários valores para cada combinação possível das GROUP BYcolunas e não tem como dizer qual desses valores você gostaria de ver.

    Nota para nós humanos: na prática, é possível que para todas as linhas em cada um de seus grupos, na realidade todos os valores sejam exatamente os mesmos. No entanto, os bancos de dados geralmente precisam decidir como obterão os dados antes de realmente começarem a obtê-los; e, nesse ponto, não há como saber se todos os ar_famivalores de cada grupo serão iguais. Então, tem que saber lidar com valores diferentes com antecedência.

    By the way - você deve ser capaz de tirar as constantes da GROUP BYcláusula em sua segunda consulta (o ""e os múltiplos 0s). Como são sempre iguais, não podem alterar o agrupamento das linhas.


    Quanto à sua segunda pergunta, a partir do SQL Server 2012, você tem acesso a uma função semelhante lá. O nome é um pouco diferente: LAST_VALUE()em vez de LAST(). Além disso, LAST_VALUE()é uma "função de janela"; ele requer uma OVER()cláusula, definindo os grupos com os quais trabalha e a ordem que usará, e os resultados são calculados para cada linha no conjunto de resultados, não para um grupo inteiro.

    Você teria que criar uma consulta complicada (ou, mais provavelmente, um conjunto de consultas aninhadas) para capturar valores não agrupados do último registro visto em cada grupo.

    Na prática, esses valores parecem ser de utilidade limitada. Se você está agregando o total de vendas dos vendedores em quatro locais diferentes, realmente importa que o nome do último vendedor tenha sido "Tony Warner"? Especialmente porque é possível que você execute a mesma consulta dois dias depois, com os mesmos dados subjacentes, gerando os mesmos resultados de grupo para totais e subtotais - mas observando que o nome do último vendedor era "Frank Northrup"? Pelo menos no SQL Server, o SQL classificará os dados em vários grupos para obter os valores agregados e aplicará o ORDER BYque você especificou; mas depende de você qual é essa ordem. Se oORDER BYnão inclui a coluna da qual você está obtendo o último valor ou algo que está vinculado a um valor específico, a "última" linha pode ser diferente cada vez que você chama a função, mesmo no mesmo conjunto de dados.

    Ainda assim, obviamente, algumas pessoas acham que vale a pena usar. Eu posso suspeitar que essas pessoas realmente não entendem o que estão recebendo de volta, ou (pior) o que as pessoas olhando para seus resultados vão supor, mas talvez haja algum valor definido para comandar que eu simplesmente não estou vendo. Para mim, se os resultados são basicamente aleatórios, não vejo o valor.

    • 2

relate perguntas

  • SQL Server - Como as páginas de dados são armazenadas ao usar um índice clusterizado

  • Preciso de índices separados para cada tipo de consulta ou um índice de várias colunas funcionará?

  • Quando devo usar uma restrição exclusiva em vez de um índice exclusivo?

  • Quais são as principais causas de deadlocks e podem ser evitadas?

  • Como determinar se um Índice é necessário ou necessário

Sidebar

Stats

  • Perguntas 205573
  • respostas 270741
  • best respostas 135370
  • utilizador 68524
  • Highest score
  • respostas
  • Marko Smith

    conectar ao servidor PostgreSQL: FATAL: nenhuma entrada pg_hba.conf para o host

    • 12 respostas
  • Marko Smith

    Como fazer a saída do sqlplus aparecer em uma linha?

    • 3 respostas
  • Marko Smith

    Selecione qual tem data máxima ou data mais recente

    • 3 respostas
  • Marko Smith

    Como faço para listar todos os esquemas no PostgreSQL?

    • 4 respostas
  • Marko Smith

    Listar todas as colunas de uma tabela especificada

    • 5 respostas
  • Marko Smith

    Como usar o sqlplus para se conectar a um banco de dados Oracle localizado em outro host sem modificar meu próprio tnsnames.ora

    • 4 respostas
  • Marko Smith

    Como você mysqldump tabela (s) específica (s)?

    • 4 respostas
  • Marko Smith

    Listar os privilégios do banco de dados usando o psql

    • 10 respostas
  • Marko Smith

    Como inserir valores em uma tabela de uma consulta de seleção no PostgreSQL?

    • 4 respostas
  • Marko Smith

    Como faço para listar todos os bancos de dados e tabelas usando o psql?

    • 7 respostas
  • Martin Hope
    Jin conectar ao servidor PostgreSQL: FATAL: nenhuma entrada pg_hba.conf para o host 2014-12-02 02:54:58 +0800 CST
  • Martin Hope
    Stéphane Como faço para listar todos os esquemas no PostgreSQL? 2013-04-16 11:19:16 +0800 CST
  • Martin Hope
    Mike Walsh Por que o log de transações continua crescendo ou fica sem espaço? 2012-12-05 18:11:22 +0800 CST
  • Martin Hope
    Stephane Rolland Listar todas as colunas de uma tabela especificada 2012-08-14 04:44:44 +0800 CST
  • Martin Hope
    haxney O MySQL pode realizar consultas razoavelmente em bilhões de linhas? 2012-07-03 11:36:13 +0800 CST
  • Martin Hope
    qazwsx Como posso monitorar o andamento de uma importação de um arquivo .sql grande? 2012-05-03 08:54:41 +0800 CST
  • Martin Hope
    markdorison Como você mysqldump tabela (s) específica (s)? 2011-12-17 12:39:37 +0800 CST
  • Martin Hope
    Jonas Como posso cronometrar consultas SQL usando psql? 2011-06-04 02:22:54 +0800 CST
  • Martin Hope
    Jonas Como inserir valores em uma tabela de uma consulta de seleção no PostgreSQL? 2011-05-28 00:33:05 +0800 CST
  • Martin Hope
    Jonas Como faço para listar todos os bancos de dados e tabelas usando o psql? 2011-02-18 00:45:49 +0800 CST

Hot tag

sql-server mysql postgresql sql-server-2014 sql-server-2016 oracle sql-server-2008 database-design query-performance sql-server-2017

Explore

  • Início
  • Perguntas
    • Recentes
    • Highest score
  • tag
  • help

Footer

AskOverflow.Dev

About Us

  • About Us
  • Contact Us

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve