সমস্ত রেকর্ড নির্বাচন করুন, উপস্থিত থাকলে টেবিল A ​​এর সাথে যোগ দিন, টেবিল বি না থাকলে


20

সুতরাং এখানে আমার পরিস্থিতি:

আমি আমার একটি প্রকল্পের জন্য স্থানীয়করণের উপর কাজ করছি, এবং সাধারণত আমি সি # কোডে এটি করতে যাব, তবে আমি এসকিউএল এ আরও কিছু করতে চাই যেহেতু আমি আমার এসকিউএলকে কিছুটা চেপে ধরার চেষ্টা করছি।

পরিবেশ: এসকিউএল সার্ভার 2014 স্ট্যান্ডার্ড, সি # (.NET 4.5.1)

দ্রষ্টব্য: প্রোগ্রামিংয়ের ভাষা নিজেই অপ্রাসঙ্গিক হওয়া উচিত, আমি কেবল এটি সম্পূর্ণতার জন্য অন্তর্ভুক্ত করছি।

তাই আমি যা চেয়েছিলাম তা বাছাই করেছিলাম, তবে আমি যে পরিমাণে চাইছিলাম তা নয়। JOINমৌলিকগুলি ব্যতীত যে কোনও এসকিউএল এস করেছি সেহেতু এটি একটি সময় হয়েছে (কমপক্ষে এক বছর) হয়েছে এবং এটি বেশ জটিলJOIN

এখানে ডাটাবেসের প্রাসঙ্গিক টেবিলগুলির একটি চিত্র রয়েছে। (আরও অনেক কিছু রয়েছে তবে এই অংশটির জন্য প্রয়োজনীয় নয়))

ডাটাবেস ডায়াগ্রামে

চিত্রটিতে বর্ণিত সমস্ত সম্পর্ক ডাটাবেসে সম্পূর্ণ - PKএবং FKসীমাবদ্ধতাগুলি সমস্ত সেটআপ এবং অপারেটিং। বর্ণিত কোনও কলামই nullসক্ষম নয়। সমস্ত টেবিলের স্কিমা রয়েছেdbo

এখন, আমার কাছে একটি কোয়েরি রয়েছে যা আমি যা চাই তা প্রায় করে: এটির কোনও আইডি SupportCategoriesএবং কোনও আইডি দেওয়াLanguages , তবে হয় এটি ফিরে আসবে:

যদি যে স্ট্রিং এর জন্য যে ভাষা (অর্থাত একটি ডান-সঠিক অনুবাদ StringKeyId-> StringKeys.Idবিদ্যমান, এবং মধ্যে LanguageStringTranslations StringKeyId, LanguageIdএবং StringTranslationIdসমন্বয় বিদ্যমান, তাহলে এটি লোড StringTranslations.Textযে জন্যStringTranslationId

তাহলে LanguageStringTranslations StringKeyId, LanguageIdএবং StringTranslationIdসমন্বয় হয়নি না অস্তিত্ব, তাহলে এটি লোড StringKeys.Nameমান। Languages.Idএকটি দেওয়া হয়integer

আমার জিজ্ঞাসাটি, এটি কোনও গোলমাল হোক, নিম্নরূপ:

SELECT CASE WHEN T.x IS NOT NULL THEN T.x ELSE (SELECT
    CASE WHEN dbo.StringTranslations.Text IS NULL THEN dbo.StringKeys.Name ELSE dbo.StringTranslations.Text END AS Result
FROM dbo.SupportCategories
    INNER JOIN dbo.StringKeys
        ON dbo.SupportCategories.StringKeyId = dbo.StringKeys.Id
    INNER JOIN dbo.LanguageStringTranslations
        ON dbo.StringKeys.Id = dbo.LanguageStringTranslations.StringKeyId
    INNER JOIN dbo.StringTranslations
        ON dbo.StringTranslations.Id = dbo.LanguageStringTranslations.StringTranslationId
WHERE dbo.LanguageStringTranslations.LanguageId = 38 AND dbo.SupportCategories.Id = 0) END AS Result FROM (SELECT (SELECT
    CASE WHEN dbo.StringTranslations.Text IS NULL THEN dbo.StringKeys.Name ELSE dbo.StringTranslations.Text END AS Result
FROM dbo.SupportCategories
    INNER JOIN dbo.StringKeys
        ON dbo.SupportCategories.StringKeyId = dbo.StringKeys.Id
    INNER JOIN dbo.LanguageStringTranslations
        ON dbo.StringKeys.Id = dbo.LanguageStringTranslations.StringKeyId
    INNER JOIN dbo.StringTranslations
        ON dbo.StringTranslations.Id = dbo.LanguageStringTranslations.StringTranslationId
WHERE dbo.LanguageStringTranslations.LanguageId = 5 AND dbo.SupportCategories.Id = 0) AS x) AS T

সমস্যা হল এটা আমার প্রদান করতে সক্ষম নয় সব এর SupportCategoriesএবং তাদের নিজ নিজ StringTranslations.Textযদি উপস্থিত থাকে, বা তাদের StringKeys.Nameযদি এটা অস্তিত্ব ছিল না। এটি তাদের যে কোনও একটি সরবরাহের ক্ষেত্রে উপযুক্ত, তবে একেবারেই নয়। মূলত, এটি প্রয়োগ করা হয় যে কোনও ভাষাতে যদি কোনও নির্দিষ্ট কীটির জন্য অনুবাদ না থাকে তবে ডিফল্টটি হ'ল অনুবাদটি StringKeys.Nameকোনটি হয় StringKeys.DefaultLanguageId। (আদর্শভাবে, এটি এমনকি এটি করে না, পরিবর্তে অনুবাদটি লোড করুন StringKeys.DefaultLanguageId, যা বাকি প্রশ্নের জন্য সঠিক দিক নির্দেশিত হলে আমি নিজেই করতে পারি))

আমি এটিতে প্রচুর সময় ব্যয় করেছি এবং আমি জানি আমি যদি এটি কেবল # # তে লিখি তবে (যেমন আমি সাধারণত করি) এখনই এটি সম্পন্ন হবে। আমি এসকিউএল এ এটি করতে চাই এবং আমার পছন্দ মতো আউটপুট পেতে আমার সমস্যা হচ্ছে।

কেবলমাত্র সতর্কতাই, আমি প্রয়োগ করা প্রকৃত প্রশ্নের সংখ্যা সীমাবদ্ধ করতে চাই। সমস্ত কলামগুলি সূচিবদ্ধ এবং যেমন আমি আপাতত তাদের পছন্দ করি এবং বাস্তব চাপ-পরীক্ষা ছাড়া আমি এগুলি আরও সূচী করতে পারি না।

সম্পাদনা: অন্য দ্রষ্টব্য, আমি যতটা সম্ভব ডাটাবেসটিকে স্বাভাবিক করার চেষ্টা করছি, তাই আমি যদি এড়াতে পারি তবে জিনিসগুলি নকল করতে চাই না।

উদাহরণ ডেটা

সূত্র

dbo.SupportCategories (সম্পূর্ণ):

Id  StringKeyId
0   0
1   1
2   2

dbo.Languages ​​(185 টি রেকর্ড, কেবল উদাহরণের জন্য দুটি দেখায়):

Id  Abbreviation    Family  Name    Native
38  en  Indo-European   English English
48  fr  Indo-European   French  français, langue française

ডিবিও ভাষাগুলি স্ট্রিং ট্রান্সলেশনস (পুরোটি):

StringKeyId LanguageId  StringTranslationId
0   38  0
1   38  1
2   38  2
3   38  3
4   38  4
5   38  5
6   38  6
7   38  7
1   48  8 -- added as example

dbo.StringKeys (সম্পূর্ণ):

Id  Name    DefaultLanguageId
0   Billing 38
1   API 38
2   Sales   38
3   Open    38
4   Waiting for Customer    38
5   Waiting for Support 38
6   Work in Progress    38
7   Completed   38

dbo.StringTransferences (সম্পূর্ণ):

Id  Text
0   Billing
1   API
2   Sales
3   Open
4   Waiting for Customer
5   Waiting for Support
6   Work in Progress
7   Completed
8   Les APIs -- added as example

বর্তমান আউটপুট

নীচের সঠিক কোয়েরি দেওয়া, এটি ফলাফল:

Result
Billing

পছন্দসই আউটপুট

আদর্শভাবে, আমি নির্দিষ্টগুলি বাদ দিতে এবং সেগুলির সমস্তটি SupportCategories.Idপেতে সক্ষম হতে চাই (ভাষা 38 Englishব্যবহার করা হলেও, বা 48 Frenchবা এই মুহুর্তে অন্য কোনও ভাষা):

Id  Result
0   Billing
1   API
2   Sales

অতিরিক্ত উদাহরণ

আমি French(যেমন অ্যাড ) এর জন্য স্থানীয়করণ যুক্ত 1 48 8করার পরে LanguageStringTranslations, আউটপুটটি পরিবর্তিত হবে (দ্রষ্টব্য: এটি উদাহরণস্বরূপ, সম্ভবত আমি একটি স্থানীয় স্ট্রিং যুক্ত করব StringTranslations) (ফরাসি উদাহরণ সহ আপডেট):

Result
Les APIs

অতিরিক্ত আকাঙ্ক্ষিত আউটপুট

উপরের উদাহরণটি দেওয়া, নিম্নলিখিত আউটপুটটি পছন্দসই হবে (ফরাসি উদাহরণ সহ আপডেট করা):

Id  Result
0   Billing
1   Les APIs
2   Sales

(হ্যাঁ, আমি প্রযুক্তিগতভাবে জানি এটি একটি ধারাবাহিকতার দৃষ্টিকোণ থেকে ভুল, তবে পরিস্থিতিটি এটি পছন্দ করবে would

সম্পাদনা:

ছোট আপডেট হয়েছে, আমি dbo.Languagesটেবিলের কাঠামো পরিবর্তন Id (int)করেছি, এবং এটি থেকে কলামটি ফেলেছি এবং এর সাথে প্রতিস্থাপন করেছি Abbreviation(যা এখন নামকরণ করা হয়েছেId , এবং সমস্ত সম্পর্কিত বিদেশী-কী এবং সম্পর্কগুলি আপডেট হয়েছে)। প্রযুক্তিগত দৃষ্টিকোণ থেকে, এই টেবিলটি আইএসও 63৩৯-১ কোডগুলিতে সীমাবদ্ধ, এগুলি শুরু করার জন্য অনন্য, এই কারণে আমার মতে এটি আরও উপযুক্ত সেটআপ।

TL; ড

তাই: প্রশ্ন হলো, কীভাবে আমি রিটার্ন এই প্রশ্নের সাথে সংশোধন পারে সবকিছু থেকে SupportCategoriesএবং তারপর পারেন আসতে StringTranslations.Textযে জন্য StringKeys.Id, Languages.Idসমন্বয়, বাStringKeys.Name এটা করেন তাহলে না রয়েছে?

আমার প্রাথমিক ধারণাটি হ'ল আমি কোনওভাবে বর্তমান কোয়েরিকে অন্য সাময়িক ধরণের জন্য অন্য সাবকোয়ারি হিসাবে কাস্ট করতে পারি এবং এই ক্যোয়ারীটিকে অন্য SELECTবিবৃতিতে আবদ্ধ করতে এবং দুটি ক্ষেত্র নির্বাচন করতে চাই ( SupportCategories.Idএবং Result)।

যদি আমি কিছু না পাই তবে আমি কেবলমাত্র আদর্শ পদ্ধতিটিই ব্যবহার করব যা আমি সাধারণত SupportCategoriesআমার সি # প্রকল্পে সমস্ত লোড করতে পারি এবং তারপরে আমি প্রতিটিটির বিরুদ্ধে ম্যানুয়ালি উপরে থাকা কোয়েরিটি চালাই SupportCategories.Id

যে কোনও এবং সমস্ত পরামর্শ / মন্তব্য / সমালোচনা করার জন্য ধন্যবাদ।

এছাড়াও, এটি অযৌক্তিকভাবে দীর্ঘ হওয়ার জন্য আমি ক্ষমাপ্রার্থী, আমি কেবল কোনও অস্পষ্টতা চাই না। আমি প্রায়শই স্ট্যাকওভারফ্লোতে থাকি এবং এমন প্রশ্নগুলি দেখি যার মধ্যে পদার্থের অভাব থাকে, এখানে সে ভুলটি করার ইচ্ছা ছিল না।

উত্তর:


16

এখানে আমি প্রথম উপস্থিতিটি নিয়ে এসেছি:

DECLARE @ChosenLanguage INT = 48;

SELECT sc.Id, Result = MAX(COALESCE(
   CASE WHEN lst.LanguageId = @ChosenLanguage      THEN st.Text END,
   CASE WHEN lst.LanguageId = sk.DefaultLanguageId THEN st.Text END)
)
FROM dbo.SupportCategories AS sc
INNER JOIN dbo.StringKeys AS sk
  ON sc.StringKeyId = sk.Id
LEFT OUTER JOIN dbo.LanguageStringTranslations AS lst
  ON sk.Id = lst.StringKeyId
  AND lst.LanguageId IN (sk.DefaultLanguageId, @ChosenLanguage)
LEFT OUTER JOIN dbo.StringTranslations AS st
  ON st.Id = lst.StringTranslationId
  --WHERE sc.Id = 1
  GROUP BY sc.Id
  ORDER BY sc.Id;

মূলত, নির্বাচিত ভাষার সাথে মেলে এমন সম্ভাব্য স্ট্রিংগুলি পান এবং সমস্ত ডিফল্ট স্ট্রিং পান, তারপরে সমষ্টি করুন যাতে আপনি কেবল প্রতি একটিকে বেছে নেনId - নির্বাচিত ভাষার উপর অগ্রাধিকার দিন, তারপরে ডিফল্টটিকে ফলব্যাক হিসাবে গ্রহণ করুন।

আপনি সম্ভবত UNION/ এর সাথে একই জিনিস করতে পারেন EXCEPTতবে আমার সন্দেহ হয় এটি প্রায়শই সর্বদা একই বস্তুর বিরুদ্ধে একাধিক স্ক্যানের দিকে পরিচালিত করবে।


12

একটি বিকল্প সমাধান যা INহারুনের উত্তরে এবং গ্রুপিং এড়ায় :

DECLARE 
    @SelectedLanguageId integer = 48;

SELECT 
    SC.Id,
    SC.StringKeyId,
    Result =
        CASE
            -- No localization available
            WHEN LST.StringTranslationId IS NULL
            THEN SK.Name
            ELSE
            (
                -- Localized string
                SELECT ST.[Text]
                FROM dbo.StringTranslations AS ST
                WHERE ST.Id = LST.StringTranslationId
            )
        END
FROM dbo.SupportCategories AS SC
JOIN dbo.StringKeys AS SK
    ON SK.Id = SC.StringKeyId
LEFT JOIN dbo.LanguageStringTranslations AS LST
    WITH (FORCESEEK) -- Only for low row count in sample data
    ON LST.StringKeyId = SK.Id
    AND LST.LanguageId = @SelectedLanguageId;

যেমনটি উল্লেখ করা হয়েছে, স্যাম্পল ডেটা সরবরাহের সাথে টেবিলের FORCESEEKকম কার্ডিনালিটির কারণে ইঙ্গিতটি কেবল সবচেয়ে দক্ষ দেখানোর পরিকল্পনা পাওয়ার প্রয়োজন LanguageStringTranslations। আরও সারি সহ, অপ্টিমাইজার প্রাকৃতিকভাবে একটি সূচক অনুসন্ধান করবে।

কার্যকর করার পরিকল্পনা নিজেই একটি আকর্ষণীয় বৈশিষ্ট্য রয়েছে:

হত্যা পরিকল্পনা

পাস গত বাইরের উপর সম্পত্তি মাধ্যমে মানে যে একটি লুকআপ যোগদানের StringTranslationsটেবিল শুধুমাত্র সঞ্চালিত হয় যদি একটি সারিতে পূর্বে পাওয়া যায়নি LanguageStringTranslationsটেবিল। অন্যথায়, এই যোগদানের অভ্যন্তরীণ দিকটি বর্তমান সারিটির জন্য পুরোপুরি এড়িয়ে গেছে।

টেবিল ডিডিএল

CREATE TABLE dbo.Languages
(
    Id integer NOT NULL,
    Abbreviation char(2) NOT NULL,
    Family nvarchar(96) NOT NULL,
    Name nvarchar(96) NOT NULL,
    [Native] nvarchar(96) NOT NULL,

    CONSTRAINT PK_dbo_Languages
        PRIMARY KEY CLUSTERED (Id)
);

CREATE TABLE dbo.StringTranslations
(
    Id bigint NOT NULL,
    [Text] nvarchar(128) NOT NULL,

    CONSTRAINT PK_dbo_StringTranslations
    PRIMARY KEY CLUSTERED (Id)
);

CREATE TABLE dbo.StringKeys
(
    Id bigint NOT NULL,
    Name varchar(64) NOT NULL,
    DefaultLanguageId integer NOT NULL,

    CONSTRAINT PK_dbo_StringKeys
    PRIMARY KEY CLUSTERED (Id),

    CONSTRAINT FK_dbo_StringKeys_DefaultLanguageId
    FOREIGN KEY (DefaultLanguageId)
    REFERENCES dbo.Languages (Id)
);

CREATE TABLE dbo.SupportCategories
(
    Id integer NOT NULL,
    StringKeyId bigint NOT NULL,

    CONSTRAINT PK_dbo_SupportCategories
        PRIMARY KEY CLUSTERED (Id),

    CONSTRAINT FK_dbo_SupportCategories
    FOREIGN KEY (StringKeyId)
    REFERENCES dbo.StringKeys (Id)
);

CREATE TABLE dbo.LanguageStringTranslations
(
    StringKeyId bigint NOT NULL,
    LanguageId integer NOT NULL,
    StringTranslationId bigint NOT NULL,

    CONSTRAINT PK_dbo_LanguageStringTranslations
    PRIMARY KEY CLUSTERED 
        (StringKeyId, LanguageId, StringTranslationId),

    CONSTRAINT FK_dbo_LanguageStringTranslations_StringKeyId
    FOREIGN KEY (StringKeyId)
    REFERENCES dbo.StringKeys (Id),

    CONSTRAINT FK_dbo_LanguageStringTranslations_LanguageId
    FOREIGN KEY (LanguageId)
    REFERENCES dbo.Languages (Id),

    CONSTRAINT FK_dbo_LanguageStringTranslations_StringTranslationId
    FOREIGN KEY (StringTranslationId)
    REFERENCES dbo.StringTranslations (Id)
);

নমুনা তথ্য

INSERT dbo.Languages
    (Id, Abbreviation, Family, Name, [Native])
VALUES
    (38, 'en', N'Indo-European', N'English', N'English'),
    (48, 'fr', N'Indo-European', N'French', N'français, langue française');

INSERT dbo.StringTranslations
    (Id, [Text])
VALUES
    (0, N'Billing'),
    (1, N'API'),
    (2, N'Sales'),
    (3, N'Open'),
    (4, N'Waiting for Customer'),
    (5, N'Waiting for Support'),
    (6, N'Work in Progress'),
    (7, N'Completed'),
    (8, N'Les APIs'); -- added as example

INSERT dbo.StringKeys
    (Id, Name, DefaultLanguageId)
VALUES
    (0, 'Billing', 38),
    (1, 'API', 38),
    (2, 'Sales', 38),
    (3, 'Open', 38),
    (4, 'Waiting for Customer', 38),
    (5, 'Waiting for Support', 38),
    (6, 'Work in Progress', 38),
    (7, 'Completed', 38);

INSERT dbo.SupportCategories
    (Id, StringKeyId)
VALUES
    (0, 0),
    (1, 1),
    (2, 2);

INSERT dbo.LanguageStringTranslations
    (StringKeyId, LanguageId, StringTranslationId)
VALUES
    (0, 38, 0),
    (1, 38, 1),
    (2, 38, 2),
    (3, 38, 3),
    (4, 38, 4),
    (5, 38, 5),
    (6, 38, 6),
    (7, 38, 7),
    (1, 48, 8); -- added as example
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.