Just nu i M3-nätverket
Gå till innehåll

Magnus Ahlkvist

Medlem
  • Antal inlägg

    1 245
  • Gick med

  • Senaste besök

Om Magnus Ahlkvist

  • Medlemstitel
    SQL Server-nerd
  • Födelsedag 1976-05-13

Kontaktinformation

  • Hemsida
    http://www.underlandet.com/SqlServer

Profil

  • Kön
    Man
  • Ort
    Enköping
  • Intressen
    Löpning och SQL Server (som utövare), Fotboll (som åskådare)

Senaste profilbesöken

4 967 profilvisningar
  1. Om ID inte har några luckor så kan du göra: SELECT t1.Datum, t1.Raknare, t1.Raknare - t2.Raknare as Enheter FROM Tabell1 t1 LEFT JOIN Tabell1 t2 ON t1.ID = t2.ID -1 Annars får du nog använda en Subquery: SELECT t1.Datum, t1.Raknare, t1.Raknare - IFNULL(( SELECT t2.Raknare FROM Tabell1 t2 WHERE t2.id < t1.id ORDER BY t2.id DESC LIMIT 1 ),t1.Raknare) FROM Tabell1 t1 ORDER BY id Jag har inte MySQL så jag har inte kunnat testa att syntaxen funkar. Men idén är densamma oavsett databasmotor.
  2. Jag är inte säker på att jag förstår. Kan du ge exempel på hur "Enheter" ska set ut i ditt exempel? Vad är det för databasserver och version?
  3. Vad är ParNr? Du har OrtNr som gemensamma kolumner, inte ParNr, såvitt du har berättat.
  4. Vad är det som inte funkar med "FROM tbl1 INNER JOIN tbl2 ON Tbl1.Object = Tbl2.Object AND Tbl1.OrtNr = Tbl2.OrtNr " _ ??
  5. Inte säker på att jag förstår. Du har alltså Produkt, Antal och AntalIn i tabellen och vill få ut Product, Antal, AntalIn och Differensen mellan AntalIn och Antal? I så fall: SELECT Produkt, Antal, AntalIn, AntalIn - Antal AS [Diff] FROM tabellen
  6. Och vad var i så fall felet med INNER JOIN som jag föreslog? SELECT Tabell1.*, Tabell2.ortsnamn FROM Tabell1 INNER JOIN Tabell2 ON Tabell1.Object = Tabell2.Object AND Tabell1.Ortnr = Tabell2.Ortnr Om inte det är vad du är ute efter, berätta i så fall, baserat på exempeldata vilket indata som ska ge vilket resultat och vad med detta förslag som inte blir rätt.
  7. Om du ger några exempel på data i tabell1 och tabell2, och exempel på förväntat resultat så är det lättare att hjälpa. Om jag förstått rätt vill du ha ut alla rader i Tabell1 och om det finns ett ortsnamn som matchar från Tabell2 så ska det med också, i annat fall vill du ha NULL som ortsnamn. I så fall kan man göra: SELECT Tabell1.*, Tabell2.ortsnamn FROM Tabell1 LEFT JOIN Tabell2 ON Tabell1.Object = Tabell2.Object AND Tabell1.Ortnr = Tabell2.Ortnr Är du istället ute efter att bara ha med de rader där det finns ett matchande Ortnamn ändrar du LEFT JOIN till INNER JOIN.
  8. Då ska vi se om vi får till det. Först har jag gjort en funktion för Nummer-tabellen. Eller snarare använt och modifierat en funktion som någon skrivit och som jag brukar lägga in i Model-databasen så att jag får med den överallt: CREATE function [dbo].[Numbers](@n int) RETURNS @t TABLE(n int primary key) AS BEGIN; WITH CTE1 AS( SELECT 1 as n UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 ),CTE2 AS( SELECT ROW_NUMBER() OVER(ORDER BY c1.n) as n FROM CTE1 c1 --10 CROSS JOIN CTE1 c2 --100 CROSS JOIN CTE1 c3 --1000 CROSS JOIN CTE1 c4 --10000 CROSS JOIN CTE1 c5 --100000 CROSS JOIN CTE1 c6 --1000000 CROSS JOIN CTE1 c7 --10000000 ) INSERT INTO @t (n) SELECT TOP(@n) n FROM CTE2 ORDER BY n RETURN; END Här är ett nytt försök, som jag testkört och får samma resultat med som jag får med din exempelkod. set datefirst 1 DECLARE @Date datetime SET @Date = '2011-01-01' SELECT datepart(week,dateadd(day,numbers.n -1,@Date)) as [Week], SUM(CASE TypeOfInvoice WHEN 'Kredit' THEN 1 ELSE 0 END) AS [OpenKredits], SUM(CASE TypeOfInvoice WHEN 'Debet' THEN 1 ELSE 0 END) AS [OpenDebets] FROM dbo.Invoice i INNER JOIN dbo.Numbers(1000) as Numbers ON DATEADD(day,numbers.n -1,@date) <= CURRENT_TIMESTAMP AND datename(WEEKDAY,DATEADD(day,numbers.n -1,@date))='Monday' AND YEAR(CreatedDateTime)=YEAR(@date) WHERE i.CreatedDateTime <= DATEADD(day,numbers.n -1,@date) AND (i.[ResolvedDateTime] > DATEADD(day,numbers.n -1,@date) OR i.[ClosedDateTime] > DATEADD(day,numbers.n -1,@date)) group by datepart(week,dateadd(day,numbers.n -1,@Date)) ORDER BY [Week] Detta ger samma resultat som att köra: SET DATEFIRST 1 DECLARE @Date datetime DECLARE @Year int SET @Date = '2011-01-01' SET @Year = YEAR(@Date) WHILE YEAR(@Date) = @Year BEGIN IF DATENAME(DW, @Date) = 'Monday' AND @Date<=GetDate() BEGIN SELECT datepart(week,@Date) [Week], SUM(CASE TypeOfInvoice WHEN 'Kredit' THEN 1 ELSE 0 END) AS [Kred], SUM(CASE TypeOfInvoice WHEN 'Debet' THEN 1 ELSE 0 END) AS [Deb] FROM dbo.Invoice WHERE [CreatedDateTime] <= @Date AND ([ResolvedDateTime] > @Date OR [ClosedDateTime] > @Date) END SET @Date = DATEADD(d, 1, @Date) END
  9. Helt riktigt med DATANAME, fel av mig. Jag har säkert gjort någon slags vurpa i skallen i mitt förslag. Men posta CREATE-script för tabellen, lite exempeldata och förväntat resultat så ska vi nog få till det.
  10. Förutom att du borde akta dig för SQL Injection och därmed skriva om din kod så att den använder ADODB.Command för att exekvera koden och skicka strId som en parameter.. Mer om detta här: https://www.owasp.org/index.php/Reviewing_Code_for_SQL_Injection För det SQL-relaterade: Du producerar SQL som ser ut ungefär såhär: SELECT tbl_Medlemmar.medlemsId, tbl_Medlemmar.medlemsNamn FROM tbl_Medlemmar WHERE tbl_Medlemmar.omrade1Id AND tbl_Medlemmar.omrade2Id AND tbl_Medlemmar.omrade3Id = 10 Dels är det ogiltig SQL - du måste sätta villkoret för varje jämförelse: SELECT tbl_Medlemmar.medlemsId, tbl_Medlemmar.medlemsNamn FROM tbl_Medlemmar WHERE tbl_Medlemmar.omrade1Id =10 AND tbl_Medlemmar.omrade2Id =10 AND tbl_Medlemmar.omrade3Id = 10 Men jag antar att du inte vill att både Område1, Område2 OCH Område3 ska vara 10 (som jag har i mitt exempel), utan att det räcker att en av dem är 10? I så fall SELECT tbl_Medlemmar.medlemsId, tbl_Medlemmar.medlemsNamn FROM tbl_Medlemmar WHERE tbl_Medlemmar.omrade1Id =10 OR tbl_Medlemmar.omrade2Id =10 OR tbl_Medlemmar.omrade3Id = 10 Men som sagt - se till att din kod inte är öppen för SQL Injection, det är den nu. Jag tycker också att din databasdesign lämnar en del övrigt att önska. Om en medlem kan ha flera områden och ett område kan ha flera medlemmar så ska man skapa en kopplingstabell, där man lägger in MedlemID och OmrådeID för varje koppling. Din nuvarande lösning är fastlåst till tre och exakt tre kopplingar.
  11. Du vinner en hel del på att använda en nummer-tabell. Jag tror att nedanstående funkar för dig och är riktigt effektivt jämfört med din nuvarande lösning. Vad den gör är att först skapa ett dynamiskt resultatset med nummer från 0 till 999. Sedan används denna nummer-tabell för att inkrementera det datum du satt. Jag har inte på något sätt testat lösningen nedan, men om det inte funkar får du gärna posta dels DDL för din tabell, dels några INSERTS med exempeldata så att jag kan testa innan jag postar ett förslag Ett tips till är också att sätta språk först i koden, så att måndag alltid stavas 'Monday'. Annars blir det så bökigt när man försöker använda koden i en databas med svenska som språk. SET DATEFIRST 1 DECLARE @Date datetime SET @Date = '2011-01-01' ;WITH N1 as ( SELECT 1 as s UNION SELECT 2 as s UNION SELECT 3 as s UNION SELECT 4 as s UNION SELECT 5 as s UNION SELECT 6 as s UNION SELECT 7 as s UNION SELECT 8 as s UNION SELECT 9 as s UNION SELECT 10 as s ), N2 AS( SELECT 1 as s FROM N1 CROSS JOIN N1 as n2 CROSS JOIN N1 as n3 ), Numbers AS( SELECT ROW_NUMBER() OVER(ORDER BY s) as N FROM N2 ) SELECT [Week], SUM(CASE TypeOfInvoice WHEN 'Kredit' THEN 1 ELSE 0 END) AS [OpenKredits], SUM(CASE TypeOfInvoice WHEN 'Debet' THEN 1 ELSE 0 END) AS [OpenDebets] FROM tblInvoices i INNER JOIN Numbers ON i.CreatedDateTime <= DATEADD(day,Numbers.N,@date) AND DATEADD(day,Numbers.N,@date) <= CURRENT_TIMESTAMP AND DATEPART(WEEKDAY,DATEADD(day,Numbers.N,@date))='Monday' AND (i.[ResolvedDateTime] > DATEADD(day,Numbers.N,@date) OR i.[ClosedDateTime] > DATEADD(day,Numbers.N,@date)) AND YEAR(CreatedDateTime)=YEAR(@date)
  12. För det första: Använd aldrig ntext. Använd nvarchar(MAX) istället för ntext. Likaledes ska du använda varchar(MAX) istället för text. Detta för att text och ntext ALLTID lagras utanför den page som resten av raden ligger på, medan varchar(MAX) och nvarchar(MAX) lagrar så mycket som får plats på samma page som resten av raden och resten utanför. Mycket, mycket ofta är en sträng som lagras i varchar(MAX) eller nvarchar(MAX) så liten att den får plats inom samma page som raden. Då är sökningen selektering och till och med filtrering (WHERE) mot strängarna snabbare. För det andra: Utan att veta mer om hur länga strängar du brukar ha, hur dina sökningar ser ut och kanske även vilka planer som SQL Server genererar för din procedur är det svårt att komma med några bra råd.
  13. Utan att veta mer om vilka tabeller som drabbats är det självklart svårt att säga, men jag lutar nog åt SQL Injection. Jag har drabbats av det flera gånger i system som jag tagit över, att script-taggar injiceras i alla varchar(max)-fält genom HTTP-GET. Det är ofta svårt att se i loggarna, eftersom variabeln som skickas in är binär-kodad. Här finns en artikel som beskriver hur det funkar: http://www.bloombit.com/Articles/2008/05/ASCII-Encoded-Binary-String-Automated-SQL-Injection.aspx
  14. Funkar det att använda ROW_NUMBER()? Dvs, funkar nedanstående kod? För i så fall går det att lösa med en sub-query. Men om nedanstående inte funkar betyder det att ROW_NUMBER() inte implementerats i MySQL, och då har jag inga bra förslag. Testa alltså nedanstående: SELECT id, titel, bskrvn, prio, dtm, ROW_NUMBER() OVER(ORDER BY prio) as RowNum
  15. En Common Table Expression kräver att _föregående_ statement avslutats med ett semikolon. Eftersom SQL Server aldrig krävt det förut är det många som inte har för vana att avsluta föregående statement med semikolon och därför använder man ofta ett semikolon för att inleda en CTE-deklaration. Jag vet inte om MySQL implementerar varken fönster-funktionen ROW_NUMBER eller Common Table Expressions.
×
×
  • Skapa nytt...