2016-08-08 46 views
0

Ich habe das Problem, dass ich 12 Max Zeilen aus 3 Tabellen Union Daten benötigen. Wenn jedoch in der Tabelle keine festen Zeilen vorhanden sind, sollten andere Tabellen für die verbleibenden Zeilen berücksichtigt werden.Top 12 von Union Abfragen filtern max 12 Zeilen MS Sql

Zum Beispiel: Ich habe 3 Tabellen Produkt Kategorie Hersteller

Fall 1: Wenn alle 10 Zeilen jeweils als wir wählen soll vier Zeilen aus jeder Tabelle. Fall 2: Wenn die Produkttabelle 3 Zeilen hat und die Kategorie ein Hersteller 5 Zeilen hat , dann sollte es jeweils 3 von Produkt und 5 von Kategorie oder Hersteller auswählen. Fall 3: Alle haben weniger als 4 Zeilen als so viele verfügbare Zeilen angezeigt.

Bitte helfen Sie mir, dies zu erreichen. Ich poste meine gespeicherte Prozedur, die ich bis jetzt erstellt habe.

Create PROCEDURE [dbo].[GetRowsfromtables] 
    @SearchTerms nvarchar(150) 
AS 
BEGIN 

create table #search (id int identity ,ids int, productname nvarchar(200), categoryname nvarchar(200), tagname nvarchar(200), SeName nvarchar(200), displayorder int) 
insert into #search 
    Select Top 12 p.Id as ids, p.name as productname, '' as categoryname, '' as tagname, '' as SeName, 0 as displayorder from Product p where p.Published = 1 and p.Deleted = 0 and name like '%' + @SearchTerms + '%' 

    union 

    Select Top 12 c.id as ids, '' as productname, c.name as categoryname, '' as tagname, '' as SeName , 1 as displayorder from Category c where c.Published = 1 and c.Deleted = 0 and Name like '%' + @SearchTerms + '%' 

    union 

    Select Top 12 t.id as ids, '' as productname, '' as categoryname, t.Name as tagname, '' as SeName, 2 as displayorder 
       from Manufacturer 
     where Name like '%' + @SearchTerms + '%' 



    Select id, ids,productname,categoryname, tagname, SeName, tagpcount,tagproductid, 
    '' as ThumbnailImage, displayorder, (Select count(*) from #search where displayorder = 0) as ptotal, 
    (Select count(*) from #search where displayorder = 1) as ctotal, 
    (Select count(*) from #search where displayorder = 2) as tagtotal, 
     row_number() over(partition by displayorder order by id) as rn 
     from #search 

     order by displayorder 

    drop table #search 
END 
+0

'TOP' ohne' ORDER BY' gibt Ihnen, was auch immer die Suchmaschine wählt. – HABO

+0

Sie sind fast da.Ihre Abfrage wählt aus # Suche aus und wendet eine Bestellung an (die Spalte, die Sie alias rn nennen), verwendet sie dann aber nicht. Ordnen Sie nach rn und fügen Sie der SELECT-Anweisung TOP 12 hinzu. –

Antwort

1

Sie können die Fensterfunktion verwenden ROW_NUMBER die Datensätze innerhalb der Union zu sequenzieren. Dann, um das mit der Zeilennummer:

/* Generate 13 sample records: 
*  Product   (4) 
*  Category  (6) 
*  Manufacturer (3) 
*/ 
WITH Product AS 
    (
     -- Sample product records. 
     SELECT 
      Id 
     FROM 
      (
       VALUES 
        (1), 
        (2), 
        (3), 
        (4) 
      ) AS x(Id) 
    ), 
    Category AS 
    (
     -- Sample category records. 
     SELECT 
      Id 
     FROM 
      (
       VALUES 
        (1), 
        (2), 
        (3), 
        (4), 
        (5), 
        (6) 
      ) AS x(Id) 
    ), 
    Manufacturer AS 
    (
     -- Sample manufacturer records. 
     SELECT 
      Id 
     FROM 
      (
       VALUES 
        (1), 
        (2), 
        (3) 
      ) AS x(Id) 
    ) 
SELECT TOP 12 
    * 
FROM 
    (
      SELECT 
       ROW_NUMBER() OVER (ORDER BY ID) AS rn, 
       'P' AS Tbl, 
       Id 
      FROM 
       Product 

     UNION ALL 

      SELECT 
       ROW_NUMBER() OVER (ORDER BY ID) AS rn, 
       'C' AS Tbl, 
       Id 
      FROM 
       Category 

     UNION ALL 

      SELECT 
       ROW_NUMBER() OVER (ORDER BY ID) AS rn, 
       'M' AS Tbl, 
       Id 
      FROM 
       Manufacturer 
    ) AS u 
ORDER BY 
    rn 
; 

Die Reihenfolge von kehren alle Datensätze 1 nummerierten zuerst, dann 2 und so weiter. Dies liefert so genau wie die Quelldaten eine Mischung.

BEARBEITEN TOP von jeder der Unterabfragen entfernt. Ich versuchte SQL zu helfen, indem ich die Anzahl der Datensätze beschränkte, auf die eine Zeilennummer angewendet werden musste. Aber die ROW_NUMBER wird vor der Spitze angewendet, was dies zu einer sinnlosen Übung macht. Meine Unterabfragen fehlten auch eine ORDER BY-Klausel. Ohne diese gibt es keine garantierte Ordnung, die "Spitze" zu einer sinnlosen Aussage macht.

+0

Das mache ich schon. Ich verwende row_number, um die Nummerierung zu erhalten. Aber ich bin nicht in der Lage, genaue Aufzeichnungen zu holen. Dies ist mein Fall: –

+0

Ich brauche das, wenn 12 Produkte da sind und 10 Kategorien auch da sind. Dann sollte es 6 Produkte und 6 Kategorien auswählen. Und wenn 12 Produkte, 10 Kategorien und 5 Hersteller, dann sollte es 4 Produkte, 4 Kategorien und 4 Hersteller wählen –

+0

Das wird das tun. Was ich hier gemacht habe, sind drei Zeilennummern. Jede Tabelle hat also eine Aufzeichnung 1, 2, 3 usw. Die oberste Anweisung gibt nur die ersten 12 zurück, die aus 1,1,2,2,3,3,4,4,5,5, 6,6 wenn nur zwei der Tabellen Datensätze haben. –

0

In jeder Ihrer Fragen, die Sie row_number(), basierend auf der Sortierreihenfolge zur Zeit für TOP verwendet n bestimmen konnte - dann Sie

CASE WHEN row_number() OVER(...) <= 4 THEN 1 ELSE 2 END AS sorter 

Entfernen Sie die TOP tun ein CASE auf der Grundlage der row_number n in jeder Fall.

Nachdem Sie Ihre Vereinigung von 3 Tabellen durchgeführt haben, nehmen Sie die TOP 12 aus der UNION als Unterabfrage, und bestellen Sie sie durch Sortierer ASC, NEWID(). Auf diese Weise haben Sie garantiert 4 beliebige Tabellen, wo sie existieren, und Randoms von anderen Tabellen, um die Zahlen

z.B.

SELECT TOP 12 DQ. * FROM ('{Abfrage}') DQ ORDER DQ.sorter ASC, newid()

1

Wie in den Kommentaren erwähnt, müssen Sie eine ORDER BY verwenden, wenn Sie TOP verwenden, oder Sie haben keine Möglichkeit festzustellen, welche oberen Zeilen Sie erhalten. Es ist auch nicht wirklich notwendig, hier eine temporäre Tabelle zu erstellen, damit Sie sie auswählen und dann löschen können. Ich habe etwas (ok gut viel) weißen Raum um Ihr Original hinzugefügt, so dass es einfacher ist, die Straße zu sehen und zu pflegen. So etwas sollte wirklich nah an dem sein, was Sie danach haben.

Eine Sache ist wichtig, dass Sie einige Spalten in Ihrer ursprünglichen Abfrage definiert haben, die nicht in Ihrer definierten temporären Tabelle waren. Keine Ahnung, was du mit denen machen willst, also habe ich sie einfach dort gelassen.

Select top 12 id 
    , ids 
    , productname 
    , categoryname 
    , tagname 
    , SeName 
    , tagpcount 
    , tagproductid 
    , '' as ThumbnailImage 
    , displayorder 
    , ptotal = sum(case when displayorder = 0 then 1 else 0 end) 
    , ctotal = sum(case when displayorder = 1 then 1 else 0 end) 
    , tagtotal = sum(case when displayorder = 2 then 1 else 0 end) 
    , row_number() over(partition by displayorder order by id) as rn 
from 
(   
    Select Top 12 p.Id as ids 
     , p.name as productname 
     , '' as categoryname 
     , '' as tagname 
     , '' as SeName 
     , 0 as displayorder 
    from Product p 
    where p.Published = 1 
     and p.Deleted = 0 
     and name like '%' + @SearchTerms + '%' 
    ORDER BY p.name --or whatever column 

    union ALL 

    Select Top 12 c.id as ids 
     , '' as productname 
     , c.name as categoryname 
     , '' as tagname 
     , '' as SeName 
     , 1 as displayorder 
    from Category c 
    where c.Published = 1 
     and c.Deleted = 0 
     and Name like '%' + @SearchTerms + '%' 
    ORDER BY c.name --or whatever column 

    union ALL 

    Select Top 12 t.id as ids 
     , '' as productname 
     , '' as categoryname 
     , t.Name as tagname 
     , '' as SeName 
     , 2 as displayorder 
    from Manufacturer 
    where Name like '%' + @SearchTerms + '%' 
    ORDER BY t.Name --or whatever column 
) x 
group by id 
    , ids 
    , productname 
    , categoryname 
    , tagname 
    , SeName 
    , tagpcount 
    , tagproductid 
    , displayorder 
order by displayorder 
+0

Vielen Dank für die Antwort. Diese Abfrage erhält nur die obersten 12 Zeilen. Also, wenn es 12 Produkte gibt, dann habe ich nur diese. –

+0

Ich brauche das, wenn 12 Produkte da sind und 10 Kategorien auch da sind. Dann sollte es 6 Produkte und 6 Kategorien auswählen. Und wenn 12 Produkte, 10 Kategorien und 5 Tags, dann sollte es 4 Produkte, 4 Kategorien und 4 Tags auswählen. –

+0

Dann müssen Sie Details über Ihre Tabellen veröffentlichen, damit wir etwas haben, mit dem wir arbeiten können. Hier ist ein großartiger Ort, um anzufangen. http://spaghettidba.com/2015/04/24/how-to-post-a-t-sql-question-on-a-public-forum/ –