2008-11-12 11 views
21

J'ai besoin de savoir comment retourner une ligne par défaut si aucune ligne n'existe dans une table. Quelle serait la meilleure façon de faire cela? Je ne renvoie qu'une seule colonne de cette table particulière pour obtenir sa valeur.Comment définir une ligne par défaut pour une requête qui ne renvoie aucune ligne?

Modifier: Ce serait SQL Server.

+0

Quel serveur de base de données utilisez-vous, SQL Server, Oracle, MySQL? – duckworth

+3

Si vous utilisez SQL Server, pourquoi accepter une réponse qui ne fonctionne que sur Oracle? –

Répondre

21

Dans Oracle:

SELECT val 
FROM myTable 
UNION ALL 
SELECT 'DEFAULT' 
FROM dual 
WHERE NOT EXISTS (SELECT * FROM myTable) 

Ou bien:

SELECT NVL(MIN(val), 'DEFAULT') 
FROM myTable 
1

Voulez-vous retourner une ligne complète? La ligne par défaut doit-elle avoir des valeurs par défaut ou peut-elle être une ligne vide? Voulez-vous que la ligne par défaut ait la même structure de colonne que la table en question?

En fonction de vos besoins, vous pourriez faire quelque chose comme ceci:

1) exécuter la requête et de mettre les résultats dans une table temporaire (ou variable de table) 2) vérifier si la table temporaire a des résultats 3) sinon, retourner une ligne vide en effectuant une instruction select similaire à celui (dans SQL Server):

select '' as columnA, '' as columnB, '' as columnC from #tempTable 

Où COLUMNA, ColumnB et ColumnC sont vos noms de colonnes réels.

1

I figured it out, et il devrait également fonctionner pour d'autres systèmes aussi. C'est une variation de la réponse de WW.

select rate 
from d_payment_index 
where fy = 2007 
    and payment_year = 2008 
    and program_id = 18 
union 
select 0 as rate 
from d_payment_index 
where not exists(select rate 
        from d_payment_index 
        where fy = 2007 
        and payment_year = 2008 
        and program_id = 18) 
+0

Le seul problème avec cette solution est que vous exécutez la recherche deux fois. Une alternative serait de stocker votre résultat dans une variable et de ne renvoyer la valeur par défaut que si le nombre de lignes de la première requête était égal à zéro. – duckworth

+0

Le seul autre problème est que je cours cela dans le code, donc une seule instruction est la meilleure. Mais oui, je suis d'accord avec vous. –

+1

Selon l'image la plus grande, vous pouvez réellement vouloir un OUTER JOIN ici. Si c'est dans une boucle à travers un jeu d'enregistrements, il y a probablement de meilleurs moyens. –

9

Ce serait éliminer la requête de sélection de courir deux fois et mieux pour la performance:

Declare @rate int 

select 
    @rate = rate 
from 
    d_payment_index 
where 
    fy = 2007 
    and payment_year = 2008 
    and program_id = 18 

IF @@rowcount = 0 
    Set @rate = 0 

Select @rate 'rate' 
+0

thats bonne réponse ... –

2

méthode de balayage Une table en utilisant une jointure gauche de la valeur par défaut actuals:

CREATE TABLE [stackoverflow-285666] (k int, val varchar(255)) 

INSERT INTO [stackoverflow-285666] 
VALUES (1, '1-1') 
INSERT INTO [stackoverflow-285666] 
VALUES (1, '1-2') 
INSERT INTO [stackoverflow-285666] 
VALUES (1, '1-3') 
INSERT INTO [stackoverflow-285666] 
VALUES (2, '2-1') 
INSERT INTO [stackoverflow-285666] 
VALUES (2, '2-2') 

DECLARE @k AS int 
SET @k = 0 

WHILE @k < 3 
    BEGIN 
     SELECT @k AS k 
       ,COALESCE(ActualValue, DefaultValue) AS [Value] 
     FROM (
       SELECT 'DefaultValue' AS DefaultValue 
       ) AS Defaults 
     LEFT JOIN (
        SELECT val AS ActualValue 
        FROM  [stackoverflow-285666] 
        WHERE k = @k 
       ) AS [Values] 
       ON 1 = 1 

     SET @k = @k + 1 
    END 

DROP TABLE [stackoverflow-285666] 

Donne la sortie:

k   Value 
----------- ------------ 
0   DefaultValue 

k   Value 
----------- ------------ 
1   1-1 
1   1-2 
1   1-3 

k   Value 
----------- ------------ 
2   2-1 
2   2-2 
12

Si votre requête de base devrait revenir qu'une seule ligne, alors vous pouvez utiliser cette astuce:

select NVL(MIN(rate), 0) AS rate 
from d_payment_index 
where fy = 2007 
    and payment_year = 2008 
    and program_id = 18 

(Oracle code, pas sûr si NVL est la bonne fonction pour SQL Server.)

+0

ISNULL est le SQL Server équivalent à NVL ... :-) –

+5

La question est de savoir comment retourner les valeurs par défaut quand il n'y a pas de lignes retournées. – WarrenT

+0

Cette requête peut toujours produire 0 enregistrements si aucun enregistrement ne correspond à la clause 'where'. Votre NVL/ISNULL convertira uniquement les valeurs null à 0 lorsqu'un enregistrement existe et que sa valeur est ** null **. –

6

Que diriez-vous ceci:

SELECT DEF.Rate, ACTUAL.Rate, COALESCE(ACTUAL.Rate, DEF.Rate) AS UseThisRate 
FROM 
    (SELECT 0) DEF (Rate) -- This is your default rate 
LEFT JOIN (
    select rate 
    from d_payment_index 
    --WHERE 1=2 -- Uncomment this line to simulate a missing value 

    --...HERE IF YOUR ACTUAL WHERE CLAUSE. Removed for testing purposes... 
    --where fy = 2007 
    -- and payment_year = 2008 
    -- and program_id = 18 
) ACTUAL (Rate) ON 1=1 

Résultats

Taux valides sur

Rate  Rate  UseThisRate 
----------- ----------- ----------- 
0   1   1 

Taux par défaut Utilisé

Rate  Rate  UseThisRate 
----------- ----------- ----------- 
0   NULL  0 

test

DDL
CREATE TABLE d_payment_index (rate int NOT NULL) 
INSERT INTO d_payment_index VALUES (1) 
0

Insérez vos valeurs par défaut dans une variable de table, puis mise à jour unique ligne de ce tableVar avec un match de votre table réelle. Si une ligne est trouvée, tableVar sera mis à jour; sinon, la valeur par défaut reste. Retourne la variable de la table.

---=== The table & its data 
    CREATE TABLE dbo.Rates (
     PkId int, 
     name varchar(10), 
     rate decimal(10,2) 
    ) 
    INSERT INTO dbo.Rates(PkId, name, rate) VALUES (1, 'Schedule 1', 0.1) 
    INSERT INTO dbo.Rates(PkId, name, rate) VALUES (2, 'Schedule 2', 0.2) 

est ici la solution:

---=== The solution 
CREATE PROCEDURE dbo.GetRate 
    @PkId int 
AS 
BEGIN 
    DECLARE @tempTable TABLE (
    PkId int, 
    name varchar(10), 
    rate decimal(10,2) 
) 

--- [1] Insert default values into @tempTable. PkId=0 is dummy value 
INSERT INTO @tempTable(PkId, name, rate) VALUES (0, 'DEFAULT', 0.00) 

--- [2] Update the single row in @tempTable with the actual value. 
---  This only happens if a match is found 
UPDATE @tempTable 
    SET t.PkId=x.PkId, t.name=x.name, t.rate = x.rate 
    FROM @tempTable t INNER JOIN dbo.Rates x 
    ON t.PkId = 0 
    WHERE x.PkId = @PkId 

SELECT * FROM @tempTable 
END 

Test du code:

EXEC dbo.GetRate @PkId=1  --- returns values for PkId=1 
EXEC dbo.GetRate @PkId=12314 --- returns default values 
Questions connexes