Καταρχήν, είναι αδύνατο να αποθηκεύσεις μαξιλαράκια σε ελληνικά, κυριλικά, αγγλικά στην ίδια στήλη varchar, καθώς όλα τα codepages έχουν χαρακτήρες που δεν εμφανίζονται στα άλλα. Οπότε ή θα χρειαστείς διαφορετικές στήλες/πίνακες για το καθένα, με διαφορετικό collation ή θα πρέπει να χρησιμοποιήσεις varbinary(max) για να σώσεις το Unicode ως bytes. Και οι δύο είναι γεμάτες μειονεκτήματα.
Ξεκινώντας από τη δεύτερη λύση, αυτό που προσπαθείς να κάνεις:
- Δεν κερδίζεις τίποτε σε χώρο, αφού είσαι αναγκασμένος να σώζεις 2 bytes ανά χαρακτήρα
- Για να δείξεις τα δεδομένα, πάλι σε NVARCHAR θα τα μετατρέψεις
- Χάνεις τη δυνατότητα αναζήτησης στο πεδίο πέρα από το απλό '='. Δεν θα μπορείς να ψάξεις για "Μαξιλαράκια%" ή οτιδήποτε παρόμοιο
- Περιορίζεις δραματικά τη δυνατότητα indexing καθώς συγκρίσεις του στυλ 'από έως', 'μεγαλύτερο','μικρότερο' παύουν να δουλεύουν.
- Αν προσπαθήσεις να κάνεις σύγκριση με την decoded τιμή χάνεις τα indexes - εκτός και αν μετατρέπεις όλα τα κριτήρια αναζήτησης σε binary πρώτα
- Οποιεσδήποτε συγκρίσεις *δεν* θα καταλαβαίνουν τις σχέσεις μεταξύ πχ. i και I. Διαφορετικά bytes σημαίνει ανισότητα και τελείωσες. Που σημαίνει "Μαξιλαράκια"<>"ΜΑΞΙΛΑΡΑΚΙΑ"
- Μειωμένη απόδοση της βάσης γιατί τα blobs αποθηκεύονται εκτός του table row. Που σημαίνει κάθε φορά που θα θέλεις να δείξεις τα μαξιλαράκια η βάση θα πρέπει να κάνει διπλή δουλειά
- Ακατάλυπτα δεδομένα. Προφανώς
- Μεγάλη πιθανότητα καταστροφής των δεδομένων, αρκεί ένας να κάνει μία εγγραφή με λάθος τρόπο, πχ να προσπαθήσει να κάνει CONVERT όπως δοκίμασες κι εσύ.
Για να κάνεις τη μετατροπή από/προς μπορείς να χρησιμοποιήσεις την CONVERT βάζοντας όμως ως τύπο το NVARCHAR, ποτέ VARCHAR για να αποφύγεις το μπάχαλο με τα διαφορετικά codepages. Για παράδειγμα:
declare @myParam nvarchar(40)=N'ВЪЗГЛАВНИЦА'
SELECT CONVERT(VARBINARY(40),@myParam);
----------------------------------------------------------------------------------
0x12042A04170413041B04100412041D04180426041004
SELECT CONVERT(NVARCHAR(40),0x12042A04170413041B04100412041D04180426041004);
----------------------------------------
ВЪЗГЛАВНИЦА
Προσοχή στον τύπο της μεταβλητής. Είναι nvarchar και δεν πρέπει να αλλάξει, διαφορετικά θα έχεις πάλι το πρόβλημα της απώλειας χαρακτήρων κατά τη μετατροπής από ένα codepage σε άλλο.
Μπορείς να προσπαθήσεις να κάνεις το ίδιο και σε κώδικα, αλλά το θέμα παραμένει. Τα δεδομένα πρέπει να μετακινούνται πάντα από Unicode σε binary, ποτέ προσπάθεια μετατροπής σε varchar. Αυτό σημαίνει ότι οποιοδήποτε query, ADO.NET command parameter ή stored procedure θα πρέπει να δουλεύει είτε με varbinary είτε με nvarchar αλλιώς θα έχεις απώλειες.
Όσο για την πρώτη λύση, μπορείς να προσθέσεις ένα ακόμα πεδίο varchar για κάθε γλώσσα που θέλεις να υποστηρίξεις με COLLATION συμβατό με τη γλώσσα. Αν κατά λάθος αποθηκεύσεις δεδομένα που δεν ταιριάζουν, τα έχασες. Όταν αποθηκεύεις varchar θα πρέπει να φροντίζεις να θέτεις και το COLLATION σε SQL. Αν αποθηκεύεις nvarchar ο SQL Server θα κάνει τη μετατροπή σωστά, φτάνει να μην βρεθούν άκυροι χαρακτήρες (πχ. ελληνικά και ρώσικα στην αγγλική στήλη).
Φυσικά αυξάνει η πολυπλοκότητα, το μέγεθος των πινάκων, η πιθανότητα λάθους, αλλά τουλάχιστον μπορείς να διαβάσεις τα δεδομένα
Ουσιαστικές λύσεις τώρα:
-
Αν το "δεν γίνεται" το λέει το αφεντικό, βρες άλλη δουλειά.
-
Αν το λέει ο manager, υπολόγισε το κόστος σε ανθρωποώρες, το δικό σου για την υλοποίηση και το κόστος από λάθη (συν το marketing cost αν τα μαξιλαράκια εμφανιστούν σαν κουτάκια) και πες του ότι θα πρέπει να το αναλάβει αυτός
-
Αν το λέει ο κατασκευαστής της εφαρμογής που χρησιμοποιείς, πες του να τη διορθώσει. Αν αρνείται, χρέωσε του τις ώρες που θα χρειαστείς για να τη διορθώσεις εσύ
-
Αν αρνείται, βρες άλλη. Υπάρχουν και άνθρωποι που ξέρουν από βάσεις
-
Αν ο κατασκευαστής είναι Microsoft partner και προσπαθεί να τα ρίξει στον SQL Server και αρνείται να διορθώσει το πρόβλημα, κάρφωσε τον στην Microsoft Hellas. Θα χαρούν να του μιλήσουν
-
Μπορείς φυσικά να του κάνεις και αγωγή γιατί σου πούλησε εν γνώση του ελλατωματικό προϊόν. Το μισό DNZ θα έρθουν μάρτυρες υπέρ σου.
Παναγιώτης Καναβός, Freelancer
Twitter: http://www.twitter.com/pkanavos