2008-11-25 3 views
0

J'ai quelques tables qui sont utilisées pour consigner l'activité de l'utilisateur pour une application. Les tableaux ressemble à ceci (code pseudo de la mémoire, ne peut pas être syntaxiquement correcte):SQL Server - mise à jour d'une table avec les première et dernière lignes d'une autre table

create table activity (
    sessionid uniqueidentifier not null, 
    created smalldatetime not null default getutcdate() 
); 

create table activity_details (
    sessionid uniqueidentifier not null, 
    activity_description varchar(100) not null, 
    created smalldatetime not null default getutcdate() 
); 

Mon but est de remplir un tableau récapitulatif pour les rapports qui ressemble à ceci:

create table activity_summary (
    sessionid uniqueidentifier not null, 
    first_activity_desc varchar(100) not null, 
    last_activity_desc varchar(100) not null 
); 

Les descriptions des premières et dernières activités seraient déterminées chronologiquement. Ma première pensée est de mettre à jour le tableau de synthèse comme ceci:

truncate table activity_summary; 

insert into activity_summary (sessionid) 
select sessionid from activity; 

update table activity_summary set 
    first_activity_desc = (select top 1 activity_desc from activity_detail where sessionid = as.sessionid order by created asc), 
    last_activity_summary = (select top 1 activity_desc from activity_detail where sessionid = as.sessionid order by created desc) 
from activity_summary as; 

Cependant, cela me semble incroyablement bavard et inutile. Je ne suis pas sûr de savoir comment le réduire. Mon instinct est que je pourrais le faire d'une manière ou d'une autre dans la phrase d'insertion, mais je suis perplexe. Aucune suggestion?

Répondre

1

Il y a probablement des moyens plus efficaces de le faire aussi bien, mais cela est plus proche de votre original:

truncate table activity_summary; 

insert into activity_summary (sessionid, first_activity_desc, last_activity_summary) 
select a.sessionid 
,(select top 1 ad.activity_desc from activity_detail AS ad where ad.sessionid = a.sessionid order by ad.created asc) AS first_activity_desc 
,(select top 1 ad.activity_desc from activity_detail AS ad where ad.sessionid = a.sessionid order by ad.created desc) AS last_activity_summary 
from activity AS a; 

Quelque chose comme cela pourrait être plus efficace:

truncate table activity_summary; 

WITH firsts AS (
    SELECT ad.sessionid 
     ,ad.activity_desc 
     ,ROW_NUMBER() OVER (ORDER BY ad.created ASC) as RowNumber 
    FROM activity_detail AS ad 
) 
,lasts AS (
    SELECT ad.sessionid 
     ,ad.activity_desc 
     ,ROW_NUMBER() OVER (ORDER BY ad.created DESC) as RowNumber 
    FROM activity_detail AS ad 
) 
insert into activity_summary (sessionid, first_activity_desc, last_activity_summary) 
select a.sessionid 
    ,firsts.activity_desc 
    ,lasts.activity_desc 
from activity AS a 
INNER JOIN firsts ON firsts.sessionid = a.sessionid AND firsts.RowNumber = 1 
INNER JOIN lasts ON lasts.sessionid = a.sessionid AND lasts.RowNumber = 1 
+0

Merci. Je ne sais pas pourquoi je n'ai pas pensé à ça - je devine que je déteste juste encapsuler des instructions select comme des valeurs de colonnes comme ça aussi.Dans les deux cas, le nombre de lectures potentielles générées par la requête est énorme - c'est ce que je cherche à réduire. – Chris

+0

Je vais en faire un sans les requêtes imbriquées pour vous. –

1
insert into activity_summary 
    (sessionid, first_activity_desc, last_activity_desc) 
select 
    agg.sessionid, 
    adf.activity_description, 
    adl.activity_description 
from 
    (SELECT 
     sessionid, MIN(created) as firstcreated, MAX(created) as lastcreated 
    from 
     activity_detail group by sessionid 
    ) agg 
    JOIN 
    activity_details adf ON agg.sessionid = adf.sessionid AND agg.firstcreated = adf.created 
    JOIN 
    activity_details adl ON agg.sessionid = adl.sessionid AND agg.lastcreated = adl.created 
+0

Presque ce que je veux. Je vois cependant un gros trou dans lequel il est tout à fait possible que deux descriptions d'activités aient le même horodatage. – Chris

+0

Le même problème s'applique à l'approche du haut et du sous-paragraphe. À moins qu'il n'y ait une autre colonne (par exemple identité) ou que la date créée soit datetime (toujours pas infaillible), alors il n'y a pas d'information pour égaliser les lignes supérieures et arrières égales – gbn

+0

Vous avez raison. Peut-être que je devrais ajouter une colonne d'identité à la table de détail et min/max outre de cela. – Chris

0

En gros,

INSERT etc.

SELECT a.sessionid, d1.activity_description, d2.activity_description

de l'activité d'un

INSCRIPTION détail d1 = ON a.sessionid d1.sessionid JOIN détail d2 = ON a.sessionid d2.sessionid

EXISTE PAS OU
(CHOISIR 1 À pARTIR détails OÙ sessionid = a.sessionid ET < d1.created créé)

ET EXISTE PAS
(CHOISIR 1 À pARTIR déta il OÙ sessionid = a.sessionid ET créé> d2.created)

0

Ou,

INSERT etc.

(Description SELECT FROM détails d1 OÙ d1.sessionid = a.sessionid
ET NON EXISTE (SELECT 1 à partir de détail OÙ créé < d1.created)) AS desc1,

(SELECT à partir de la description détaillée d2 OÙ d2.sessionid = a.sessionid
AND NOT EXISTS (SELECT 1 à partir de détail d2 OÙ créé> d1. créé)) AS desc2

de l'activité d'un

(je préfère ce moi-même.)

Questions connexes