Please start any new threads on our new
site at https://forums.sqlteam.com. We've got lots of great SQL Server
experts to answer whatever question you can come up with.
| Author |
Topic |
|
cesark
Posting Yak Master
215 Posts |
Posted - 2005-04-19 : 11:17:18
|
Hi,I wrote a SP inside SQL Server so that to make a query and return the results to the ASP.NET application. This query is to display the details page of a record (an offer) in a web page, and the user will see all the details of an specified offer.Here is the SP:Use marketGOALTER PROCEDURE offer_detail@Offer_num bigint, @Reference varchar(50) output, @Company_State varchar(50) output, @Company_City varchar(100) output, @Company_name varchar(100) output, @Web_page varchar(100) output,@Activity_description varchar(500) output, @TheDate datetime output,@Family_prod varchar(50) output, @Product_name varchar(100) output, @Other_fam varchar(50) output, @Other_prod varchar(50) output,@Variety varchar(50) output, @Trade_name varchar(50) output, @Offer_title varchar(100) output, @State_place varchar(50) output, @City_place varchar(100) output, @day char(2) output,@month char(2) output, @year char(4) output,@State_origin varchar(50) output, @City_origin varchar(100) output,@Production_type varchar(50) output, @logo_cert_ecol varchar(256),@logo_cert_pi varchar(256), @DOP_IGP varchar(50), @DOP_IGP_name varchar(100), @DOP_IGP_logo varchar(256),@Private_cerificate varchar(50), @CertAut_name varchar(100), @logo_CertAut varchar(256),@CertMana_name1 varchar(50), @CertMana_name2 varchar(50), @CertMana_name3 varchar(50), @CertMana_name4 varchar(50), @CertMana_name5 varchar(50), @CertMana_name6 varchar(50), @CertMana_name7 varchar(50), @Others_cert varchar(150) AsSET NOCOUNT ON Select @Reference = Reference, @Company_State = state_user.State_name,@Company_City = city_user.City_name,@Company_name = user.Company_name, @Web_page = user.Web_page, @Activity_description = user.Activity_description,@TheDate = TheDate,@Family_prod = fam.Family_name, @Product_name = prod.Product_name,@Other_fam = Other_families, @Other_prod = Other_products, @Variety = Variety,@Trade_name = Trade_name, @Offer_title = Offer_title, @State_place = state_prod.State_name, @City_place = city_prod.City_name,@day = day,@month = month, @year = year,@State_origin = state_prodOr.State_name, @City_origin = city_prodOr.City_name,@Production_type = p_type.Production_type_name, @logo_cert_ecol = CASEWHEN offe.Production_type_num = 1 THEN path_ec.Directory_path + prod_ecol.Certificate_logo ELSE NULL END,@logo_cert_pi = CASEWHEN offe.Production_type_num = 2 THEN path_int.Directory_path + prod_int.Certificate_logo ELSE NULL END,@DOP_IGP = DI.DOP_IGP_name, @DOP_IGP_name = DI_prod.DOP_IGP_name,@DOP_IGP_logo = path_DI.Directory_path + DI_prod.Logo, @Private_cerificate = Private_cerificate, @CertAut_name = certAut.Quality_certificate_name,@logo_CertAut = path_cAut.Directory_path + certAut.Logo, @CertMana_name1 = certMana_name1.Management_cert_name,@CertMana_name2 = certMana_name2.Management_cert_name,@CertMana_name3 = certMana_name3.Management_cert_name,@CertMana_name4 = certMana_name4.Management_cert_name,@CertMana_name5 = certMana_name5.Management_cert_name,@CertMana_name6 = certMana_name6.Management_cert_name,@CertMana_name7 = certMana_name7.Management_cert_name, @Others_cert = certMana.Others_Certificates From Offers As offe JOIN Users As userOn offe.User_num = user.User_idJOIN Europe_cities As city_userOn user.City_num = city_user.City_idJOIN States As state_userOn state_user.State_id = city_user.State_num JOIN Products_names As prodOn offe.Product_num = prod.Producto_IdJOIN Families_products As famOn prod.Family_num = fam.Family_IdJOIN Europe_cities As city_prodOn offe.place_City_num = city_prod.City_idJOIN States As state_prodOn state_prod.State_id = city_prod.State_num JOIN States As state_prodOrOn offe.origin_State_num = state_prodOr.State_id JOIN Europe_cities As city_prodOrOn offe.origin_City_num = city_prodOr.City_idJOIN Production_type As p_typeOn offe.Production_type_num = p_type.Production_type_idJOIN Production_ec As prod_ecolOn prod_ecol.CCAA_num = state_prodOr.Comunity_numJOIN Path_to_directories As path_ecOn prod_ecol.Directory_path_num = path_ec.Directory_path_idJOIN Production_int As prod_intOn prod_int.CCAA_num = state_prodOr.Comunity_numJOIN Path_to_directories As path_intOn prod_int.Directory_path_num = path_int.Directory_path_idJOIN DOP_IGP_Product As DI_prodOn offe.DOP_IGP = DI_prod.DOP_IGP_Product_id JOIN DOP_IGP As DIOn DI.DOP_IGP_id = DI_prod.DOP_IGP_num JOIN Path_to_directories As path_DIOn DI_prod.Directory_path_num = path_DI.Directory_path_idJOIN Certificates_quality As certAutOn offe.Certificate_aut = certAut.Certificate_quality_idJOIN Path_to_directories As path_cAutOn certAut.Directory_path_num = path_cAut.Directory_path_idJOIN CertMana_Offers As certManaOn offe.Offer_id = certMana.Offer_numJOIN Certificates_management_Type As certMana_name1 On certMana.Certificate_Mana1 = certMana_name1.Certificate_management_idJOIN Certificates_management_Type As certMana_name2 On certMana.Certificate_Mana2 = certMana_name2.Certificate_management_idJOIN Certificates_management_Type As certMana_name3 On certMana.Certificate_Mana3 = certMana_name3.Certificate_management_idJOIN Certificates_management_Type As certMana_name4 On certMana.Certificate_Mana4 = certMana_name4.Certificate_management_idJOIN Certificates_management_Type As certMana_name5 On certMana.Certificate_Mana5 = certMana_name5.Certificate_management_idJOIN Certificates_management_Type As certMana_name6 On certMana.Certificate_Mana6 = certMana_name6.Certificate_management_idJOIN Certificates_management_Type As certMana_name7 On certMana.Certificate_Mana7 = certMana_name7.Certificate_management_idWhere Offer_id = @Offer_numSET NOCOUNT OFF GO Is this SP efficient? Or there is some redundancies or inefficient practices? It will work fast? A 75% of the returned values can be null. For example the table fields marked in bold can be null, so, many returned variables can be also null. Despite these variables are null I have to return them as I do it now? And also I have to JOIN tables as I do it now although in many cases the table fields to join them are null? Thank you,Cesar |
|
|
X002548
Not Just a Number
15586 Posts |
Posted - 2005-04-19 : 12:12:45
|
| a 28 table join...you're lucky this ain't 6.5...Is it effecient...don't know (wouldn't think so)...did you check the plan?Brett8-) |
 |
|
|
cesark
Posting Yak Master
215 Posts |
Posted - 2005-04-19 : 13:01:09
|
| Hi,I am sorry but I don' t understand anything what you mean. I am not a DB expert. Would you mind explaining for a beginner how can I do it, please? And/or the basic rules?Thanks |
 |
|
|
X002548
Not Just a Number
15586 Posts |
Posted - 2005-04-19 : 13:09:42
|
| Go in to Query Analyzer. It is an interface to SQL Server that gets installed with the client side tools.Open a connection to your databaseCut and paste the query you have in to the QA(Query Analyzer) window.Type [CTRL]+KAnd then type [CTRL]+EIt will show you how the optimizer chose the path to the data.This will tell you if it's effecient or not.BUT...to join 28 tables together, no matter how effecient just doesn't seem right.Brett8-) |
 |
|
|
DonAtWork
Master Smack Fu Yak Hacker
2167 Posts |
Posted - 2005-04-19 : 13:10:51
|
| If this is for an ASP application, perhaps instead of 20 output params, you could just return a dataset. MUCH easier to work with on the ASP.NET side.It also looks like you could cram these tables@CertMana_name1 = certMana_name1.Management_cert_name,@CertMana_name2 = certMana_name2.Management_cert_name,@CertMana_name3 = certMana_name3.Management_cert_name,@CertMana_name4 = certMana_name4.Management_cert_name,@CertMana_name5 = certMana_name5.Management_cert_name,@CertMana_name6 = certMana_name6.Management_cert_name,@CertMana_name7 = certMana_name7.Management_cert_name, into one table. I would suggest rethinking your database. |
 |
|
|
cesark
Posting Yak Master
215 Posts |
Posted - 2005-04-19 : 18:03:50
|
quote: BUT...to join 28 tables together, no matter how effecient just doesn't seem right.
But if you have a table with 200 fields, and there are 95 FOREIGN KEY‘s (fields based on the primary keys of other tables), how you can do a complete query of that table without joining a lot of tables?quote: It also looks like you could cram these tables@CertMana_name1 = certMana_name1.Management_cert_name,@CertMana_name2 = certMana_name2.Management_cert_name,@CertMana_name3 = certMana_name3.Management_cert_name,...into one table. I would suggest rethinking your database.
I join the ‘CertMana_Offers’ table to ‘Certificates_management_Type’ table 7 times because the ‘CertMana_Offers’ looks like:Cert_manaOffers_id smallintOffer_num bigintCertificate_Mana1 smallint (FOREIGN KEY = Certificate_management_id)Certificate_Mana2 smallint (FOREIGN KEY = Certificate_management_id)Certificate_Mana3 smallint (FOREIGN KEY = Certificate_management_id)Certificate_Mana4 smallint (FOREIGN KEY = Certificate_management_id)Certificate_Mana5 smallint (FOREIGN KEY = Certificate_management_id) Certificate_Mana6 smallint (FOREIGN KEY = Certificate_management_id)Certificate_Mana7 smallint (FOREIGN KEY = Certificate_management_id)Others_Certificates varchar(100) And, how you would retrieve the ‘Certificate_Mana1..7’ names which are in another table called ‘Certificates_management_Type’? Certificates_management_Type table: Certificate_management_id smallintCertificate_mana_name varchar(50) |
 |
|
|
Amethystium
Aged Yak Warrior
701 Posts |
Posted - 2005-04-20 : 07:26:23
|
quote: But if you have a table with 200 fields, and there are 95 FOREIGN KEY‘s (fields based on the primary keys of other tables), how you can do a complete query of that table without joining a lot of tables?
Forgive me, but what kind of table is this exactly?! A table with so many fields must be storing some really special information or something.Possible design modification?! Who knows... but as Brett said, if you’re having to join with 28 tables, something isn’t right somewhere.------------->>> BREAKING NEWS!!! <<<------------- Saddam Hussien has weapons of mass destruction |
 |
|
|
cesark
Posting Yak Master
215 Posts |
Posted - 2005-04-20 : 10:29:28
|
| According BOL Sql Server can have 2.000 millions of tables, 1.024 columns (fields) per table, and 8.060 bytes per row. My table have 160 fields (only a 16% of the maximum allowed capacity).Correct me if this information is wrong, but I think that a table with 160-200 fields is totally normal. Then perhaps the question is: How to deal with such tables to make queries? |
 |
|
|
Michael Valentine Jones
Yak DBA Kernel (pronounced Colonel)
7020 Posts |
Posted - 2005-04-20 : 11:09:10
|
I think the point that people are making is that you have a de-normalized database design, and that is why the queries are so difficult. Something like Certificate_Mana1 through Certificate_Mana7 is a repeating group, and not a normalized design. This is hardly ever something you want to do, and I think the difficulty in developing queries shows why.I would say in my experience that 160 columns or more is not a very normal table design. Just because you are allowed to do something does not make it a good practice.quote: Originally posted by cesark According BOL Sql Server can have 2.000 millions of tables, 1.024 columns (fields) per table, and 8.060 bytes per row. My table have 160 fields (only a 16% of the maximum allowed capacity).Correct me if this information is wrong, but I think that a table with 160-200 fields is totally normal. Then perhaps the question is: How to deal with such tables to make queries?
CODO ERGO SUM |
 |
|
|
cesark
Posting Yak Master
215 Posts |
Posted - 2005-04-20 : 11:35:15
|
About ‘CertMana_Offers’ table, perhaps the design of that table isn’ t good, but I don’ t understand why. Let me ask you why:A product offered in an offer of the ‘Offers’ table can have as far as 7 certificates plus a text field to write other certificates. For example, the product 56 (a watch) can have the Certificates Quality_A, Quality_B, Quality_C, Quality_D, Quality_E, Quality_F and Quality_G (I mean that can have 0, 2, 4 or 7 of them). This is why I have the ‘CertMana_Offers’ table:Cert_manaOffers_id smallintOffer_num bigintCertificate_Mana1 smallint (FOREIGN KEY = Certificate_management_id)Certificate_Mana2 smallint (FOREIGN KEY = Certificate_management_id)Certificate_Mana3 smallint (FOREIGN KEY = Certificate_management_id)Certificate_Mana4 smallint (FOREIGN KEY = Certificate_management_id)Certificate_Mana5 smallint (FOREIGN KEY = Certificate_management_id) Certificate_Mana6 smallint (FOREIGN KEY = Certificate_management_id)Certificate_Mana7 smallint (FOREIGN KEY = Certificate_management_id)Others_Certificates varchar(100) Because every time an offer is inserted, in this table is added a row with the offer number (in the second column) and the certificates that has. For example, if the offer 258 has a product with 4 certificates (Quality_B, Quality_D, Quality_E and Quality_G), in the ‘CertMana_Offers’ table will be stored:Cert_manaOffers_id = 267Offer_num = 258Certificate_Mana1 = 2Certificate_Mana2 = 4Certificate_Mana3 = 5 Certificate_Mana4 = 7Certificate_Mana5 = null Certificate_Mana6 = null Certificate_Mana7 = nullOthers_Certificates = null This design is wrong?About my very large 'Offers' table (160 fields), I am going to search information about such rarity. I will tell you something.Thanks |
 |
|
|
cesark
Posting Yak Master
215 Posts |
Posted - 2005-04-21 : 04:30:58
|
| I can split this table of 160 columns in 5, 6 or more tables linking them with Foreign Keys, but, What advantage I will obtain doing this? Distributing the 160 columns in smaller tables will make the query I need (of 160 fields) diminish the number of joined tables in the query? I think that it will happen the opposite.If the main problem is that I need to join too many tables to make a query, and the cause may be a de-normalized database design, Which database design allows to make a query of 150-200 fields without joining many tables? Having few Foreign Keys per table….? |
 |
|
|
Michael Valentine Jones
Yak DBA Kernel (pronounced Colonel)
7020 Posts |
Posted - 2005-04-21 : 16:27:47
|
I think a simple illustration of why the denormalized design of the Offer table is bad will make it easier to see my point.You have a Offers table with these columns, among others:Certificate_Mana1 smallint (FOREIGN KEY = Certificate_management_id)Certificate_Mana2 smallint (FOREIGN KEY = Certificate_management_id)Certificate_Mana3 smallint (FOREIGN KEY = Certificate_management_id)Certificate_Mana4 smallint (FOREIGN KEY = Certificate_management_id)Certificate_Mana5 smallint (FOREIGN KEY = Certificate_management_id) Certificate_Mana6 smallint (FOREIGN KEY = Certificate_management_id)Certificate_Mana7 smallint (FOREIGN KEY = Certificate_management_id)Others_Certificates A simple query would be to show me every offer that contains Certificate 20. The query would be something like this:Select OfferIDfrom Offerswhere Certificate_Mana1 = 20 or Certificate_Mana2 = 20 or Certificate_Mana3 = 20 or Certificate_Mana4 = 20 or Certificate_Mana5 = 20 or Certificate_Mana6 = 20 or Certificate_Mana7 = 20 or -- Assuming Others_Certificates doesn't contain -- spaces or anthing but numbers and commas -- If they do, it just gets worse. Others_Certificates like '20' or Others_Certificates like '20,%' or Others_Certificates like '%,20,%' or Others_Certificates like '%,20' Now lets change the query to show me every offer that contains Certificate 20 and not Certificate 21.Select OfferIDfrom Offerswhere ( Certificate_Mana1 = 20 or Certificate_Mana2 = 20 or Certificate_Mana3 = 20 or Certificate_Mana4 = 20 or Certificate_Mana5 = 20 or Certificate_Mana6 = 20 or Certificate_Mana7 = 20 or -- Assuming Others_Certificates doesn't contain -- spaces or anthing but numbers and commas Others_Certificates like '20' or Others_Certificates like '20,%' or Others_Certificates like '%,20,%' or Others_Certificates like '%,20' ) and ( not ( Certificate_Mana1 = 21 or Certificate_Mana2 = 21 or Certificate_Mana3 = 21 or Certificate_Mana4 = 21 or Certificate_Mana5 = 21 or Certificate_Mana6 = 21 or Certificate_Mana7 = 21 or -- Assuming Others_Certificates doesn't contain -- spaces or anthing but numbers and commas Others_Certificates like '21' or Others_Certificates like '21,%' or Others_Certificates like '%,21,%' or Others_Certificates like '%,21' )) Now, instead of this, lets assume that the Offers table design was normalized by moving the Offer Certificates to a different table with a foreigh key reference to the Offers table.Then the first query would look like this:Select OfferIDfrom Offer_Certificateswhere Certificate_management_id = 20group by OfferID And the second query would look like this:Select OfferIDfrom Offer_Certificateswhere Certificate_management_id = 20 and OfferID not in ( select OfferID from Offer_Certificates where Certificate_management_id = 21 )group by OfferID That sure is a lot simpler.Let try one last query. Show me every offer that contains Certificate 1 though 20 and not Certificate 21 or greater. I won't even bother trying it with the current Offer table, because I don't have all day.Select OfferIDfrom Offer_Certificateswhere Certificate_management_id between 1 and 20 and OfferID not in ( select OfferID from Offer_Certificates where Certificate_management_id >= 21 )group by OfferID See how much harder it is to program against against a denormalized table design?CODO ERGO SUM |
 |
|
|
cesark
Posting Yak Master
215 Posts |
Posted - 2005-04-21 : 18:49:37
|
quote: I think a simple illustration of why the denormalized design of the Offer table is bad will make it easier to see my point.You have a Offers table with these columns, among others:Certificate_Mana1 smallint (FOREIGN KEY = Certificate_management_id)Certificate_Mana2 smallint (FOREIGN KEY = Certificate_management_id)…
Where did you see that I have the Certificate_Mana1..7 columns in Offers table? I have it in a separate table with a FK reference. As I said:quote: A product offered in an offer of the ‘Offers’ table can have as far as 7 certificates plus a text field to write other certificates. For example, the product 56 (a watch) can have the Certificates Quality_A, Quality_B, Quality_C, Quality_D, Quality_E, Quality_F and Quality_G (I mean that can have 0, 2, 4 or 7 of them). This is why I have the ‘CertMana_Offers’ table:
CertMana_Offers is a separate table joined with Offers table through a FKThe thing you don’ t understand is that in that table (CertMana_Offers) there are 8 columns, 7 of them with a Foreign Key to a table with the names of the certificates (Quality_A, Quality_B, Quality_C, Quality_D, Quality_E, Quality_F and Quality_G). This means that one row of CertMana_Offers can be:Cert_manaOffers_id = 267Offer_num = 258Certificate_Mana1 = 2Certificate_Mana2 = 4Certificate_Mana3 = 5 Certificate_Mana4 = 7Certificate_Mana5 = null Certificate_Mana6 = null Certificate_Mana7 = nullOthers_Certificates = nullThis means that Offer number 258 has the certificates (Quality_B, Quality_D, Quality_E and Quality_G).And I repeat: This design is wrong? Or bad? If not is bad, Are there something wrong in my initial SP (Query) posted? |
 |
|
|
AjarnMark
SQL Slashing Gunting Master
3246 Posts |
Posted - 2005-04-21 : 19:09:26
|
| If you'll give us the actual CREATE TABLE statement for CertMana_Offers, we might be able to explain it better, but off the top of my head, why not have it structured like:Cer_manaOffers_idOffer_numCertificate_ManaAnd then have repeating rows in that table instead of all the certificate_Mana in repeating columns in one row?Repeating rows are MUCH easier to deal with in a database than repeating columns are.---------------------------EmeraldCityDomains.com |
 |
|
|
Michael Valentine Jones
Yak DBA Kernel (pronounced Colonel)
7020 Posts |
Posted - 2005-04-21 : 19:29:46
|
OK, you have CertMana_Offers in a separate table. That’s even worse, since you still have a de-normalized table with a repeating group, and you have to join to that table from Offers to get the de-normalized data.It certainly doesn't make the queries in my example any easier.I have the impression that you do not understand the concept of normalization. I really think you should start with reading the topic "SQL Database Normalization Rules" in the SQL Server Books Online.quote: Originally posted by cesark
quote: I think a simple illustration of why the denormalized design of the Offer table is bad will make it easier to see my point.You have a Offers table with these columns, among others:Certificate_Mana1 smallint (FOREIGN KEY = Certificate_management_id)Certificate_Mana2 smallint (FOREIGN KEY = Certificate_management_id)…
Where did you see that I have the Certificate_Mana1..7 columns in Offers table? I have it in a separate table with a FK reference. As I said:quote: A product offered in an offer of the ‘Offers’ table can have as far as 7 certificates plus a text field to write other certificates. For example, the product 56 (a watch) can have the Certificates Quality_A, Quality_B, Quality_C, Quality_D, Quality_E, Quality_F and Quality_G (I mean that can have 0, 2, 4 or 7 of them). This is why I have the ‘CertMana_Offers’ table:
CertMana_Offers is a separate table joined with Offers table through a FKThe thing you don’ t understand is that in that table (CertMana_Offers) there are 8 columns, 7 of them with a Foreign Key to a table with the names of the certificates (Quality_A, Quality_B, Quality_C, Quality_D, Quality_E, Quality_F and Quality_G). This means that one row of CertMana_Offers can be:Cert_manaOffers_id = 267Offer_num = 258Certificate_Mana1 = 2Certificate_Mana2 = 4Certificate_Mana3 = 5 Certificate_Mana4 = 7Certificate_Mana5 = null Certificate_Mana6 = null Certificate_Mana7 = nullOthers_Certificates = nullThis means that Offer number 258 has the certificates (Quality_B, Quality_D, Quality_E and Quality_G).And I repeat: This design is wrong? Or bad? If not is bad, Are there something wrong in my initial SP (Query) posted? CODO ERGO SUM |
 |
|
|
cesark
Posting Yak Master
215 Posts |
Posted - 2005-04-22 : 06:59:28
|
Yeah AjarnMark, I think you pointed to the real solution! To have repeating rows in CertMana_Offers table instead of having repeating columns. The normalization rule I violated is the 4a of this list: : http://msdn.microsoft.com/library/default.asp?url=/library/en-us/eqbol/eqintbol_008c.asp. Is it?But this it does’ t mean that I can’ t have more than one column in a table with the same Foreign Key in other cases, for example:Offers table:Offer_ifdUser_numProduct_numUser_city (FK city_id)Product_origin_city (FK city_id) This is correct. Isn’ t it?And I understand that if I have several columns with the same FK but they mean exactly the same (for example a set of Certificates a product can have), then it is better to repeat rows for every additional Certificate.Is all I mentioned correct?If so, the only big problem in my initial Query posted it was the CertMana_Offers table? Since I understand that make a query of 150 or 200 fields isn’ t a sin.. , and there is no way to do such queries without joining a lot of tables. Is it?Michael Valentine Jones, thanks to your last post I read this list of normalization rules http://msdn.microsoft.com/library/default.asp?url=/library/en-us/eqbol/eqintbol_008c.asp and I found the rule I violated after also read AjarnMark solution. |
 |
|
|
AjarnMark
SQL Slashing Gunting Master
3246 Posts |
Posted - 2005-04-22 : 16:46:36
|
| Cesark, I think you could make an argument for multiple references to the same FK table, but I would definitely make it a habit of double and triple checking yourself when you see that pattern happening. And definitely, when they mean the same thing, you want to extract those to a different setup.So I guess the final question is whether or not you can rearrange your table schema at this point or have to continue to suffer with the one you have for a while.---------------------------EmeraldCityDomains.com |
 |
|
|
|
|
|
|
|