سؤال

لدي بعض البيانات المتنوعة المخزنة في جدول في MS SQL Server 2005. هل لدى أي شخص رمز SQL الذي يأخذ استعلامًا كمدخلات (دعنا نقول أن الاستعلام يضمن إرجاع عمود واحد من varbinary) وإخراج البايتات إلى القرص (ملف واحد (ملف واحد لكل صف؟) أنا متأكد من أن هذا قد سُئل ألف مرة من قبل ، لكن Googling تأتي في الغالب .NET Solutions. أريد حل SQL.

هل كانت مفيدة؟

المحلول

نهج BCP لا يعمل بالنسبة لي. لا يمكن إلغاء تعديل البايتات التي تكتب إلى القرص إلى كائنات .NET التي قمت بتخزينها. هذا يعني أن البايتات على القرص ليست مكافئة لما تم تخزينه. ربما BCP يكتب نوعا من الرأس. لست واثق.

لقد وجدت الرمز التالي هنا في أسفل المقال. إنه يعمل بشكل رائع! على الرغم من أنه كان مخصصًا لصور BMP المخزنة ، إلا أنها تعمل مع أي varbinary.

DECLARE @SQLIMG VARCHAR(MAX),
    @IMG_PATH VARBINARY(MAX),
    @TIMESTAMP VARCHAR(MAX),
    @ObjectToken INT

DECLARE IMGPATH CURSOR FAST_FORWARD FOR 
        SELECT csl_CompanyLogo from mlm_CSCompanySettingsLocalizations

OPEN IMGPATH 

FETCH NEXT FROM IMGPATH INTO @IMG_PATH 

WHILE @@FETCH_STATUS = 0
    BEGIN
        SET @TIMESTAMP = 'd:\' + replace(replace(replace(replace(convert(varchar,getdate(),121),'-',''),':',''),'.',''),' ','') + '.bmp'

        PRINT @TIMESTAMP
        PRINT @SQLIMG

        EXEC sp_OACreate 'ADODB.Stream', @ObjectToken OUTPUT
        EXEC sp_OASetProperty @ObjectToken, 'Type', 1
        EXEC sp_OAMethod @ObjectToken, 'Open'
        EXEC sp_OAMethod @ObjectToken, 'Write', NULL, @IMG_PATH
        EXEC sp_OAMethod @ObjectToken, 'SaveToFile', NULL, @TIMESTAMP, 2
        EXEC sp_OAMethod @ObjectToken, 'Close'
        EXEC sp_OADestroy @ObjectToken

        FETCH NEXT FROM IMGPATH INTO @IMG_PATH 
    END 

CLOSE IMGPATH
DEALLOCATE IMGPATH

نصائح أخرى

يمكنك استخدام BCP ، وليس T-SQL ، ولكن يعمل بشكل جيد.

BCP "SELECT FileContent FROM table WHERE ID = 1" queryout "C:\file.txt" -T

أقوم بإضافة هذا للبناء على إجابة Johnopincar ، بحيث يمكن للآخرين الذين يرغبون في استخدام Linqpad الحصول على حل عمل بشكل أسرع.

/*
This LinqPad script saves data stored in a VARBINARY field to the specified folder.
1. Connect to SQL server and select the correct database in the connection dropdown (top right)
2. Change the Language to C# Program
3. Change "Attachments" to the name of your table that holds the VARBINARY data
4. Change "AttachmentBuffer" to the name of the field that holds the data
5. Change "Id" to the unique identifier field name
6. Change "1090" to the identity of the record you want to save
7. Change the path to where you want to save the file. Make sure you choose the right extension.

Notes: Windows 10 may give you "Access Denied" error when trying to save directly to C:\. Rather save to a subfolder.
*/

void Main()
{
    var context = this;
    var query = 
        from ci in context.Attachments
        where ci.Id == 1090
        select ci.AttachmentBuffer
    ;
    byte[] result = query.Single().ToArray();
    File.WriteAllBytes(@"c:\DEV\dumpfile.xlsx", result);
    Console.WriteLine("Done");
}

أعلم أنها منشور قديم ، لكنني اكتشفت سبب عدم عمل ما يلي وكيفية إصلاحه:

BCP "SELECT FileContent FROM table WHERE ID = 1" queryout "C:\file.JPG" -T -N

والسبب هو BCP PUT PREFIX طول في بداية الملف. إنه إما 4 بايت أو 8 بايت ، يعتمد على نوع البيانات من عمود fileContent (النص ، ntext ، الصورة: 4 varchar (max) ، varbinary (max): 8 الرجوع إلى https://msdn.microsoft.com/en-us/library/ms190779.aspx)

استخدم محررًا ثنائيًا ، مثل واحد في Visual Studio ، لإزالة بايت بايت ، ويعمل كل شيء تمامًا. :-)

إذا كان لديك linqpad ، فهذا يعمل:

void Main()
{
    var context = this;
    var query = 
        from ci in context.Images
        where ci.ImageId == 10
        select ci.Image
    ;
    var result = query.Single ();
    var bytes = Convert.FromBase64String(result);
    File.WriteAllBytes(@"c:\image.bmp", bytes);
}

مجرد بديل. يمكنك استخدام Toad Freeware لخادم SQL وحفظه مباشرة من المحرر.

يمكنك الذهاب إلى موقعه على الويب https://www.toadworld.com واحصل على مجاني هناك أو تجربة لمدة 30 يومًا من النسخة الكاملة. تحت التنزيل واختيار TOAD لخادم SQL.

enter image description here

يمكنك القيام ببيان تحديد منتظم في TOAD على السطر يحتوي على الصورة التي تريد حفظها. عندما ترى النتائج ، يمكنك النقر فوق عمود صورة البايت وعلى اليمين ، ترى علامة تبويب PDF إذا كان هذا مستند PDF أو على اليسار ترى علامة تبويب صورة. عند النقر فوق علامة التبويب ، يمكنك رؤية شعار حفظ في الأسفل لحفظ الصورة أو الملف.

تم تصميم SQL للعمل مع كائنات قاعدة البيانات ، لذلك من وجهة نظره لا يوجد أي شيء آخر. بالتأكيد ، هناك إجراءات ممتدة مثل xp_cmdshell يتيح لك ذلك التفاعل مع نظام التشغيل ، لكنها ملحقات ملكية وليست جزءًا من T-SQL.

ربما يكون النهج الأقرب هو استخدام سمة Filestream لأنواع ثنائية من SQL Server 2008 ، والتي تسمح بتخزين بعض الأعمدة مباشرة كملفات في مجلد بدلاً من استخدام قاعدة البيانات:

نظرة عامة على Filestream

ملحوظة تم تصميم تخزين FileStream للحفاظ على ملفات كبيرة من قاعدة البيانات من أجل زيادة الأداء ، وليس للسماح للوصول المباشر إلى الملفات (أي T-SQL لا يزال لديه مفهوم نظام الملفات). رأيي ، فإن الوصول المباشر إلى نظام الملفات من SQL سوف يهزم بعض أغراض قاعدة البيانات (بشكل رئيسي تخزين البيانات بطريقة منظمة).

لذلك أود أن أوصي باتباع نصيحة Dustin واستخدام أداة مثل BCP أو أي dumper بيانات أخرى.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top