go backarticles

Articles of SQLschool.gr Team

Πριν από τρία χρόνια είχα γράψει ένα post με αυτό το θέμα. Το συγκεκριμένο post είναι από τα δημοφιλή θα έλεγα και έχει αρκετούς, από όσο γνωρίζω, που έχουν χρησιμοποιήσει την συγκεκριμένη πρόταση.

Παρόλα αυτά όμως το παλαιό post χρειάζεται ένα refactoring καθώς από τότε που γράφτηκε μέχρι σήμερα έχουν μεσολαβήσει αρκετές αλλαγές που σε αρκετές περιπτώσεις δεν θα δουλέψει. Για αυτό σε αυτό δίνω μια νέα βελτιωμένη εκδοχή.

Αλλαγές που έχουν προκύψει από την παλαιότερη έκδοση

Πρώτη και σημαντική αλλαγή είναι το γεγονός ότι πλέον δεν υπάρχει ο Microsoft Jet 4.0 OLEDB provider σε x64. Αυτό είναι ένα θέμα καθώς αν είμαστε σε SQL Server x64 δεν θα μπορέσει η λύση να δουλέψει.

Ένα ακόμα θέμα είναι ότι πλέον τα excel files έχουν αλλάξει format από την έκδοση του Office 2007 και είναι σε xlsx format που ως γνωστό είναι xml εσωτερικά.

Αυτοί ήταν και οι βασικοί λόγοι που αποφάσισα να ασχοληθώ ξανά μαζί του.

Ο «αντικαταστάτης» του Jet

Το πρώτο πράγμα το οποίο χρειάζεται να κάνουμε είναι κατεβάσουμε και να εγκαταστήσουμε στον SQL Server ένα νέο provider που θα μπορούσαμε να πούμε ότι είναι ο «αντικαταστάτης» του Jet.

Αυτός είναι ο Microsoft Access Database Engine 2010 provider. Μπορείτε να τον κατεβάσετε από το link αυτό. Θα ήθελα όμως να διαβάσετε τα σχετικά με αυτόν στοιχεία που υπάρχουν σε αυτό, καθώς περιέχει σημαντικές πληροφορίες για το σκοπό που έχει δημιουργηθεί ο συγκεκριμένος provider.
Φυσικά θα πρέπει να κατεβάσετε αυτόν που ταιριάζει στην πλατφόρμα που είστε (x86, x64).

Ρυθμίσεις του ACE provider στον SQL Server.

Για να δουλέψει ο συγκεκριμένος provider με το σενάριο που θέλουμε και δεν είναι άλλο από το export σε excel θα πρέπει να κάνουμε κάποιες ρυθμίσεις σε αυτόν. Οι ρυθμίσεις αυτές αφορούν τα messages με αριθμούς 7399 & 7330 τα οποία θα εμφανιστούν σε όλους που θα προσπαθήσουν να εκτελέσουν την διαδικασία. Οι ρυθμίσεις αυτές αφορούν κάποια properties και μπορούν να γίνουν εκτελώντας το παρακάτω script.

 

EXEC master.dbo.sp_MSset_oledb_prop N'Microsoft.ACE.OLEDB.12.0', N'AllowInProcess', 1
EXEC master.dbo.sp_MSset_oledb_prop N'Microsoft.ACE.OLEDB.12.0', N'DynamicParameters', 1;  

Υποστήριξη των xlsx

Όπως είπα και παραπάνω το format που υπάρχει πλέον στα office files είναι σε xml. Για το λόγο αυτό θα δείτε στο κώδικα της διαδικασίας ότι κατά την δημιουργία του linked server θα πρέπει σαφέστατα να το ορίσω. Αυτό γίνεται αν στο connection string στα settings του προσθέσω την λέξης Xml μετά από την αναφορά του excel. Όπως φαίνεται στο παρακάτω  code snipet.

EXEC sp_addlinkedserver   @server = @linked_server_name
                                , @srvproduct=@server_product_name
                                , @provider=N'Microsoft.ACE.OLEDB.12.0'
                                , @datasrc=@exp_path_filename
                                , @provstr='EXCEL 12.0 Xml;HDR=YES;' ;

Η νέα λύση

Η νέα λύση πατάει στην ουσία στην προηγούμενη απλά έχω κάνει μερικές αλλαγές. Για να την χρησιμοποιήσει κανείς το πρώτο που πρέπει να κάνει είναι να φτιάξει ένα xlsx file σύμφωνα με τις ανάγκες του σε γραμμογράφηση. Αυτό όπως έχω πει και στο παλαιότερο post μπορεί να γίνει αν στην πρώτη γραμμή του excel sheet βάλω κάποιο λεκτικό στην κάθε κολώνα εν ήδη column name. Επίσης θα πρέπει, αν και δεν είναι απαραίτητο, να βάλω ένα δικό μου sheet name αντί για το γνωστό Sheet1. Αυτό το xlsx θα πρέπει να το κάνω copy σε κάποιο folder που το account του SQL Server service έχει δικαιώματα, και ο ρόλος του είναι γίνει το template για την εκτέλεση της διαδικασίας.

Όπως θα δείτε μέσα στην διαδικασία το template αυτό αντιγράφεται με άλλο όνομα και στο αντίγραφο μπαίνουν να δεδομένα.

Για να γίνει η αντιγραφή αυτή χρησιμοποιείται η xp_cmdshell. Αυτή εξ ορισμού δεν μπορεί να εκτελεστεί για λόγους που έχουν να κάνουν με την ασφάλεια. Η συγκεκριμένη procedure δίνει την δυνατότητα μέσα από τον SQL Server να εκτελεστούν commands και programs που υπάρχουν εκτός SQL Server. Γενικά την έχουμε απενεργοποιημένη και την χρησιμοποιούμε κατά βούληση εφόσον την χρειαζόμαστε. Μπορούμε να την ενεργοποιούμε πριν την εκτέλεση της διαδικασία και να την απενεργοποιούμε μετά. Δεν έχω εντάξει αυτό στην διαδικασία μου καθώς μπορεί σε κάποιο σύστημα αυτή να είναι ήδη ενεργοποιημένη και δεν θα ήταν σωστό μέσα από την διαδικασία αυτή να την κλείνω και να μην δουλεύουν άλλα που χρησιμοποιούν αυτή.
Για την ενεργοποίηση αυτής αρκεί να εκτελεστεί το παρακάτω script για την ενεργοποίηση με την τιμή 1 στο τέλος ή 0 για την απενεργοποίηση.

sp_configure 'xp_cmdshell', 1;
GO
RECONFIGURE 
GO

Η stored procedure

Το επόμενο βήμα είναι να δημιουργήσουμε την stored procedure που θα κάνει την όλη διαδικασία. Αυτή μπορούμε να την δημιουργήσουμε είστε στην βάση που εργαζόμαστε είτε ποιο κεντρικά όπως για παράδειγμα στην master database όπως ο κώδικα παρακάτω κάνει.

Η συγκεκριμένη stored procedure έχει τις εξής παραμέτρους:

@linked_server_name : Δίνουμε το όνομα του προσωρινού liked server που θα δημιουργηθεί για να γίνει η διαδικασία του export.
@server_product_name : Δίνουμε ένα string πχ ‘ExcelExportDemo’
@exp_path_filename : To full path name και file name για το αρχείο που περιέχει τα δεδομένα του export
@template : To full path name και file name για του template xlsx
@sheet_name : Το όνομα του sheet όπως είναι στο xlxs.
@columns_list : Tα ονόματα των columns χωρισμένα με comma όπως ακριβώς τα έχουμε ορίσει στο xlsx template πχ ‘id,name,contact’      , @select_query : To query που θα διαβάσει τα δεδομένα και το οποίο θα πρέπει να έχει ακριβώς τον ίδιο αριθμό σε columns όπως αυτός έχει ορισθεί στο xlsx template.

 

IF ( OBJECT_ID('sp_Export2Excel') > 0 )
BEGIN
    DROP PROC dbo.sp_Export2Excel;
END
GO

CREATE PROC dbo.sp_Export2Excel 
                          @linked_server_name nvarchar(128) -- linked server name
                        , @server_product_name nvarchar(128) -- sever product name
                        , @exp_path_filename nvarchar(1024) -- path and filename for the exported excel file
                        , @template nvarchar(1204) -- path and filename of template file
                        , @sheet_name nvarchar(64) -- the name of excel sheet
                        , @columns_list nvarchar(1024) -- the list of columns name in the excel sheet 1st line
                        , @select_query nvarchar(max) -- the query of data
                        
                        
AS
BEGIN
    SET NOCOUNT ON;

    DECLARE @cmdBuilderString nvarchar (1024);
    
    BEGIN TRY
        
        --
        -- copy empty template to exported filename
        --
        SET    @cmdBuilderString = 'copy ' + @template + ' ' + @exp_path_filename;
        EXEC xp_cmdshell @cmdBuilderString , no_output ;
        
        --
        -- if temporary linked server exists delete it
        --
        IF  EXISTS (SELECT srv.name FROM sys.servers srv 
                    WHERE srv.server_id != 0 
                    AND srv.name = @linked_server_name)
        BEGIN
            EXEC master.dbo.sp_dropserver @server=@linked_server_name
                                        , @droplogins='droplogins'
        END

        --
        -- create temporary linked server with excel file
        --
        EXEC sp_addlinkedserver   @server = @linked_server_name
                                , @srvproduct=@server_product_name
                                , @provider=N'Microsoft.ACE.OLEDB.12.0'
                                , @datasrc=@exp_path_filename
                                , @provstr='EXCEL 12.0 Xml;HDR=YES;' ;
        
        --
        -- execute import        
        --
        SET    @cmdBuilderString = 'INSERT ' 
                                + @linked_server_name + '...' 
                                + QUOTENAME(@sheet_name+'$') + ' '
                                + '('+@columns_list+')' + ' '
                                + @select_query +';';
        EXEC (@cmdBuilderString);                                

        --
        -- delete temporary linked server
        --
        EXEC master.dbo.sp_dropserver @server=@linked_server_name
                                , @droplogins='droplogins'
        
    END TRY
    --
    -- error trap
    --
    BEGIN CATCH
        SELECT      ERROR_NUMBER() AS err_number
                , ERROR_MESSAGE() AS err_message; 
    END CATCH

END
GO

Η εκτέλεση της διαδικασίας

Για να εκτελέσουμε την διαδικασία αυτή εφόσον έχουμε υλοποιήσει τα παραπάνω δεν απαιτεί τίποτα περισσότερο από την κλήση της stored procedure όπως στο παράδειγμα που ακολουθεί.

EXEC dbo.sp_Export2Excel 
                          @linked_server_name = N'ExcelData'
                        , @server_product_name = N'xlsexport'
                        , @exp_path_filename = N'C:\temp\customersX.xlsx'
                        , @template = N'C:\temp\customersX_template.xlsx'
                        , @sheet_name ='MyData'
                        , @columns_list = N'id,name,contact'
                        , @select_query = 'select customerid,companyname,contactname from northwind.dbo.customers'
        
GO


/*antonch*/


Antonios Chatzipavlis

Antonios Chatzipavlis

Antonios is a Data Solutions Consultant and Trainer. He has been working in IT since 1988. In his career, he has worked as senior developer, IT Manager, Solutions Architect and IT Consultant. Since 1995 he has been devoted on new technologies and software development tools, mainly by Microsoft, either by training company staff and colleagues or assisting them in design, development and implementation as a consultant or chief developer. He has focused in Databases and Data Science since 1995. He specialized in Microsoft SQL Server since version 6.0 in areas like SQL Server Internals, Database Design and Development, Business Intelligence and in 2010 he has started working with Azure Data Platform, NoSQL databases, Big Data Technologies and Machine Learning. He is an active member of many IT communities in Greece, answering colleagues' questions and writing articles in his web site. He is the owner of SQLschool.gr which is a community portal with a lot of information about Microsoft SQL Server. He has been a Microsoft Certified Trainer (MCT) since 2000. Microsoft honored him as MVP on Data Platform due to his activities in SQL Server since 2010. He holds a large number of Microsoft Certifications and Microsoft SQL Server Certifications since version 6.5.


Comments

user-gravatar

On 08 Nov 2012 @ 1:50 PM Γιώργος Ροζάκης wrote:

1000 thanks Αντώνη! Θα το δοκιμάσω τώρα και θα σου στείλω τ'αποτελέσματα..

Leave your comment

COMMENT

FULL NAME

EMAIL ADDRESS

We use Gravatar

WEB SITE



captcha


 

Newsletter

If you want to receive updates from us subscribe below with your email.
Follow us in
PASS chapter logo

The Official PASS Local Group for Greece

About us Contact us Terms of Use Privacy Sing in Register
sql school greece logo
© 2010-2020 All rights reserved

This site uses cookies for operational and analytics purposes only. By continuing to browse this site, you agree to their use.