كيف أقوم بعملية Upsert In Table؟
-
09-06-2019 - |
سؤال
لدي طريقة عرض تحتوي على قائمة بالوظائف، مع بيانات مثل الأشخاص الذين تم تعيينهم لهم والمرحلة التي هم فيها.أحتاج إلى كتابة إجراء مخزن يُرجع عدد الوظائف التي يمتلكها كل شخص في كل مرحلة.
لدي هذا حتى الآن (مبسط):
DECLARE @ResultTable table
(
StaffName nvarchar(100),
Stage1Count int,
Stage2Count int
)
INSERT INTO @ResultTable (StaffName, Stage1Count)
SELECT StaffName, COUNT(*) FROM ViewJob
WHERE InStage1 = 1
GROUP BY StaffName
INSERT INTO @ResultTable (StaffName, Stage2Count)
SELECT StaffName, COUNT(*) FROM ViewJob
WHERE InStage2 = 1
GROUP BY StaffName
المشكلة في ذلك هي أن الصفوف لا تتجمع.لذا، إذا كان لدى أحد الموظفين وظائف في المرحلة 1 والمرحلة 2، فهناك صفين فيResultTable.ما أود فعله حقًا هو تحديث الصف في حالة وجوده للموظف وإدراج صف جديد في حالة عدم وجوده.
هل يعرف أحد كيفية القيام بذلك، أو يمكن أن يقترح نهجا مختلفا؟أود حقًا تجنب استخدام المؤشرات للتكرار في قائمة المستخدمين (ولكن هذا هو خياري الاحتياطي).
أنا أستخدم SQL Server 2005.
يحرر:@ لي: لسوء الحظ، كان InStage1 = 1 بمثابة تبسيط.إنه يشبه إلى حد كبير حيث أن DateStarted ليس فارغًا وDateFinished هو NULL.
يحرر:@BCS: تعجبني فكرة إدراج جميع الموظفين أولاً، لذلك يتعين عليّ فقط إجراء تحديث في كل مرة.لكنني أجد صعوبة في تصحيح عبارات UPDATE هذه.
المحلول
IIRC هناك نوع من بناء جملة "On Duplicate" (قد يكون الاسم خاطئًا) والذي يتيح لك التحديث في حالة وجود صف (MySQL)
بالتناوب بعض أشكال:
INSERT INTO @ResultTable (StaffName, Stage1Count, Stage2Count)
SELECT StaffName,0,0 FROM ViewJob
GROUP BY StaffName
UPDATE @ResultTable Stage1Count= (
SELECT COUNT(*) AS count FROM ViewJob
WHERE InStage1 = 1
@ResultTable.StaffName = StaffName)
UPDATE @ResultTable Stage2Count= (
SELECT COUNT(*) AS count FROM ViewJob
WHERE InStage2 = 1
@ResultTable.StaffName = StaffName)
نصائح أخرى
في الواقع، أعتقد أنك تجعل الأمر أصعب بكثير مما هو عليه الآن.ألن يعمل هذا الرمز مع ما تحاول القيام به؟
SELECT StaffName, SUM(InStage1) AS 'JobsAtStage1', SUM(InStage2) AS 'JobsAtStage2'
FROM ViewJob
GROUP BY StaffName
يمكنك فقط التحقق من وجوده واستخدام الأمر المناسب.أعتقد أن هذا يستخدم بالفعل مؤشرًا خلف الكواليس، ولكنه أفضل ما ستحصل عليه على الأرجح:
IF (EXISTS (SELECT * FROM MyTable WHERE StaffName = @StaffName))
begin
UPDATE MyTable SET ... WHERE StaffName = @StaffName
end
else
begin
INSERT MyTable ...
end
يتمتع SQL2008 بإمكانية MERGE جديدة وهي رائعة، ولكنها ليست موجودة في عام 2005.
للحصول على نوع استعلام "مزعج" حقيقي، تحتاج إلى استخدام حالة وجود...نوع من الشيء، وهذا يعني للأسف استخدام المؤشر.
ومع ذلك، يمكنك تشغيل استعلامين، أحدهما لإجراء التحديثات في حالة وجود صف موجود، ثم إدراج الاستعلام الجديد بعد ذلك.أعتقد أن هذا النهج القائم على المجموعة سيكون أفضل إلا إذا كنت تتعامل حصريًا مع أعداد صغيرة من الصفوف.
يجب أن يجمع الاستعلام التالي في جدول النتائج الصفوف مرة أخرى.هذا على افتراض أن InStage1 وInStage2 ليسا كلاهما بالرقم "1" أبدًا.
select distinct(rt1.StaffName), rt2.Stage1Count, rt3.Stage2Count
from @ResultTable rt1
left join @ResultTable rt2 on rt1.StaffName=rt2.StaffName and rt2.Stage1Count is not null
left join @ResultTable rt3 on rt1.StaffName=rt2.StaffName and rt3.Stage2Count is not null
تمكنت من تشغيله مع مجموعة متنوعة من إجابة BCS.لم يسمح لي باستخدام متغير جدول، لذلك اضطررت إلى إنشاء جدول مؤقت.
CREATE TABLE #ResultTable
(
StaffName nvarchar(100),
Stage1Count int,
Stage2Count int
)
INSERT INTO #ResultTable (StaffName)
SELECT StaffName FROM ViewJob
GROUP BY StaffName
UPDATE #ResultTable SET
Stage1Count= (
SELECT COUNT(*) FROM ViewJob V
WHERE InStage1 = 1 AND
V.StaffName = @ResultTable.StaffName COLLATE Latin1_General_CI_AS
GROUP BY V.StaffName),
Stage2Count= (
SELECT COUNT(*) FROM ViewJob V
WHERE InStage2 = 1 AND
V.StaffName = @ResultTable.StaffName COLLATE Latin1_General_CI_AS
GROUP BY V.StaffName)
SELECT StaffName, Stage1Count, Stage2Count FROM #ResultTable
DROP TABLE #ResultTable