Database Design - Multilingual Website - mysql

I'm having a multilingual website which it's users are able to have profile in different languages, for example each user could have his profile published in "English" and "French" and "Spanish", something like LinkedIn.
Now, I'm a user who is seeing the website in "English" language, so while I go to other members profile page, I should see that member profile in "English", if that profile is not available in that language, I should see that profile in that member "main_lang".
So I have a "members" table which has a column as "published_profile_langs", in this col the languages which each member has published his profile in is gonna be stored comma separated: "english,spanish", and "main_lang" col which is the user main language (his profile is definitely published in main_lang since we're asking for details on sign up step).
In another hand, members details are stored in different tables, such as "members_details_english", "members_details_spanish", "members_details_french".
I want to join my query, but it seems it's not possible in the way which I managed, currently I need to use 2 queries for loading the members details in the mentioned above scenario, my code in "members_profile.php" is:
// FIRST QUERY
$check_member = mysql_query("SELECT main_lang, profile_published_langs FROM members WHERE id = '$this_user_id'");
while($row = mysql_fetch_array($check_member)){
$this_main_lang = $row['main_lang'];
$this_profile_published_langs = $row['profile_published_langs'];
}
$this_profile_published_langs_arr = explode(',', $this_profile_published_langs);
if(!in_array($lang, $this_profile_published_langs_arr)) $lang = $this_main_lang;
$details_table = 'members_details_' . $lang;
// SECOND QUERY
$get_details = mysql_query("SELECT * FROM $details_table WHERE member_id = '$this_user_id'");
while($row_details = mysql_fetch_array($get_details)){
//blah blah
}
Is there any better way to achieve this? maybe someway to query once and not twice? any better database structure for this scenario?
I would appreciate any kind of help

Try considering language as just another entity in the database. Use the table members to store all data not dependant on the language, and have a second table with data that is; members_i18n - short for memebers_internationalization.
In the first table you can have a column called main_language_id and use the second table to store columns for data in different languages for each member by relating to it with member_id and language_id. This way you can fetch data for each member in all languages, just their main language, or any specific set of languages you need.
Plus, you won't need to use serialized data in your tables like profile_published_langs.
So a few example queries would be:
-- Main language
SELECT *
FROM member AS m
JOIN member_i18n AS mi
ON m.member_id = mi.member_id
AND m.main_language_id = mi.language_id
-- Specific language
SELECT *
FROM member AS m
JOIN member_i18n AS mi
ON m.member_id = mi.member_id
WHERE mi.language_id = 'eng'
-- All languages
SELECT *
FROM member AS m
JOIN member_i18n AS mi
ON m.member_id = mi.member_id
EDIT:
Personally, I usually use a third table with languages that looks like this:
CREATE TABLE `language` (
`language_id` char(3) NOT NULL,
`name` varchar(30) NOT NULL,
`code2` char(2) NOT NULL,
PRIMARY KEY (`language_id`)
);
-- Sample data
INSERT INTO `language` (`language_id`, `name`, `code2`) VALUES
('deu', 'Deutsch', 'de'),
('eng', 'English', 'en');
I found it to be very useful when printing out multilingual data.
EDIT 2:
So to fetch data for a user in the "current" language and their main language, just write a single query like this:
-- Current language (i.e. 'eng') + member's main language
SELECT *
FROM member AS m
JOIN member_i18n AS mi
ON m.member_id = mi.member_id
WHERE mi.language_id = m.main_language_id
OR mi.language_id = 'eng'
You'll end up with one or two rows, depending on the member's profile.

You can have a table members (id_user, mainlang, firstname, ...) and a table profile (id_user, language, and all data in that language). and for a user you have a row for each language. Your select is like this
select * from profile where id_user = $userId and language = $lang

I would probably build a user table, a language table and a mapping table
user_main - all usual columns, witha mail language column here
language table - whatever you want to keep, code etc, plus a column-
lang table name (equivalent to your user_details_spanish etc tables)
mapping table - user id, lanague id ( a row here means that that
particular user has a profile in that language)
Now, i would agree, that you might still need two queries, but I think its much more manageable since the table name is available from the lang table, and you might keep it in session (e.g. where you let the user choose from a drop down which language to switch to, the table name can be available there itself, so that you dont have to fetch it)...
Let me know if this direction of thought helps.. perhaps I can help further...

Related

Django querysets: Excluding NULL values across multiple joins

I'm trying to avoid using extra() here, but haven't found a way to get the results I want using Django's other queryset methods.
My models relationships are as follows:
Model: Enrollment
FK to Course
FK to User
FK to Mentor (can be NULL)
Model: Course
FK to CourseType
In a single query: given a User, I'm trying to get all of the CourseTypes they have access to. A User has access to a CourseType if they have an Enrollment with both a Course of that CourseType AND an existing Mentor.
This user has 2 Enrollments: one in a Course for CourseType ID 6, and the other for a Course for CourseType ID 7, but her enrollment for CourseType ID 7 does not have a mentor, so she does not have access to CourseType ID 7.
user = User.objects.get(pk=123)
This works fine: Get all of the CourseTypes that the user has enrollments for, but don't (yet) query for the mentor requirement:
In [28]: CourseType.objects.filter(course__enrollment__user=user).values('pk')
Out[28]: [{'pk': 6L}, {'pk': 7L}]
This does not give me the result I want: Excluding enrollments with NULL mentor values. I want it to return only ID 6 since that is the only enrollment with a mentor, but it returns an empty queryset:
In [29]: CourseType.objects.filter(course__enrollment__user=user).exclude(course__enrollment__mentor=None).values('pk')
Out[29]: []
Here's the generated SQL for the last queryset that isn't returning what I want it to:
SELECT `courses_coursetype`.`id` FROM `courses_coursetype` INNER JOIN `courses_course` ON ( `courses_coursetype`.`id` = `courses_course`.`course_type_id` ) INNER JOIN `store_enrollment` ON ( `courses_course`.`id` = `store_enrollment`.`course_id` ) WHERE (`store_enrollment`.`user_id` = 3877 AND NOT (`courses_coursetype`.`id` IN (SELECT U0.`id` AS `id` FROM `courses_coursetype` U0 LEFT OUTER JOIN `courses_course` U1 ON ( U0.`id` = U1.`course_type_id` ) LEFT OUTER JOIN `store_enrollment` U2 ON ( U1.`id` = U2.`course_id` ) WHERE U2.`mentor_id` IS NULL)))
The problem, it seems, is that in implementing the exclude(), Django is creating a subquery which is excluding more rows than I want excluded.
To get the desired results, I had to use extra() to explicitly exclude NULL Mentor values in the WHERE clause:
In [36]: CourseType.objects.filter(course__enrollment__user=user).extra(where=['store_enrollment.mentor_id IS NOT NULL']).values('pk')
Out[36]: [{'pk': 6L}]
Is there a way to get this result without using extra()? If not, should I file a ticket with Django per the docs? I looked at the existing tickets and searched for this issue but unfortunately came up short.
I'm using Django 1.7.10 with MySQL.
Thanks!
Try using isnull.
CourseType.objects.filter(
course__enrollment__user=user,
course__enrollment__mentor__isnull=False,
).values('pk')
Instead of exclude() you can create complex queries using Q(), or in your case ~Q():
filter_q = Q(course__enrollment__user=user) | ~Q(course__enrollment__mentor=None)
CourseType.objects.filter(filter_q).values('pk')
This might lead to a different SQL statement.
See docs:
https://docs.djangoproject.com/en/3.2/topics/db/queries/#complex-lookups-with-q-objects

How are store/website-specific (or non-global) products attributes stored/queried in the Magento mysql database?

First of all, I know I should be using the model rather than working on the database directly. That being said, does anyone know exactly how Magento handles non-global product attributes?
I have 2 websites in core_website: Admin (website_id = 0) and Main Website (website_id =1). I also have two stores in core_store: Admin (store_id = 0) and Default Store View (store_id = 0). It seems that whether or not a product (or category?) attribute is global in scope is stored in catalog_eav_attribute.is_global. A value of 0 corresponds to a scope of "Store View," a value of 1 corresponds to "Global," and 2 corresponds to "Website." So far so good.
Now, if I wanted to get the value of a store-specific attribute like "name" (eav_attribute.attribute_id = 71; eav_attribute.backend_type = 'varchar'; catalog_eav_attribute.is_global = 0) for all my products, you would think I would do something like this:
SELECT *
FROM catalog_product_entity_varchar
WHERE attribute_id = 71
AND store_id = 1
But that returns nothing. All of the names are actually in rows with store_id = 0. As far as I can tell the only attributes in the database that are stored with store_id = 1 are 'url_key' and 'url_path'. So how does Magento store these values? And how does Magento retrieve them?
Are all values initially(or also) stored with store_id = 0 as a kind of default, until a different value than that one needs to be stored? When a store-specific value that is different from the admin value needs to be stored, does magento then create a new row with store_id = 1 (or whatever store_id it is)?
If that - or something like that - is the case, then how does Magento retrieve store-specific values? Does it check catalog_eav_attribute.is_global first for the attribute in question? If it is non-global, it could then first query with store_id = 1, and if that returns nothing, then query with the default store_id = 0?
I guess my main question is how does magento actually do it. Secondarily, why does magento do it this way instead of storing values with the actual store_id? Also, if I were to write a query, should I query both store_id = 0 and store_id = 1 and choose the right value based on whether or not the attribute is global and whether or not there is a value present for store_id = 1?
You seem to have it figured out. At least you have a good idea on how things are done.
To summarize and confirm your suspicions:
All the attribute values are stored in catalog_product_entity_* where * can be anyone of theses: decimal, int, varchar, text, datetime depending on the attribute type (backend_type).
There are also other tables that keep the data related to tier pricing and images but let's leave that for now.
Attribute table definition
Each of the tables have the following columns:
value_id - just an increment id for the table
entity_type_id - the entity type id for the product (always the same)
attribute_id - reference to the attribute
store_id - reference to the store view
entity_id - reference to the product
value - actual value
There is a unique constraint on these columns entity_id,attribute_id,store_id. This means that for one product and one attribute you can have only one value for a store view.
Now the part where you are right.
store_id = 0 means that the value stored there is a default value.
If there is no value specified for a specific store view (store_id >= 1) then this value will be used.
If the attribute is set as global then the value for store_id = 0 will be used even if you have values for store_id = 1.
Examples
To get an idea of how the values are retrieved put this code in some file and run it (make sure the flat catalog is disabled - more on that later, and make sure you created an instance of the application first using Mage::app()):
Store view attribute
$collection = Mage::getModel('catalog/product')->getCollection()
->addAttributeToFilter('name', 'some_name');
echo $collection->getSelect();
The code above means that I want to retrieve a list of products with the name some_name.
the sql query associated to the collection looks like this:
SELECT
`e`.*,
IF(at_name.value_id > 0, at_name.value, at_name_default.value) AS `name`
FROM
`catalog_product_entity` AS `e`
INNER JOIN
`catalog_product_entity_varchar` AS `at_name_default`
ON (`at_name_default`.`entity_id` = `e`.`entity_id`) AND
(`at_name_default`.`attribute_id` = '96') AND
`at_name_default`.`store_id` = 0
LEFT JOIN
`catalog_product_entity_varchar` AS `at_name`
ON (`at_name`.`entity_id` = `e`.`entity_id`) AND
(`at_name`.`attribute_id` = '96') AND
(`at_name`.`store_id` = 1)
WHERE
(IF(at_name.value_id > 0, at_name.value, at_name_default.value) = 'some_name')
Ugly huh?
Because the name attribute (id 96 in my case) is a store view scope attribute (is_global = 0) Magento joins twice with the table catalog_product_entity_varchar (the one that holds the name), once for the current store view and once for the detault store view (id = 0). adding a condition:
IF(at_name.value_id > 0, at_name.value, at_name_default.value)
So if there is no value for the store id 1, use the default value.
Global attribtue
Now let's see what happens if we filter by a global attribute.
$collection = Mage::getModel('catalog/product')->getCollection()
->addAttributeToFilter('weight', '1');
echo $collection->getSelect();
The sql printed looks like this:
SELECT
`e`.*,
`at_weight`.`value` AS `weight`
FROM
`catalog_product_entity` AS `e`
INNER JOIN
`catalog_product_entity_decimal` AS `at_weight`
ON (`at_weight`.`entity_id` = `e`.`entity_id`) AND
(`at_weight`.`attribute_id` = '101') AND
(`at_weight`.`store_id` = 0)
WHERE
(at_weight.value = '1')
So one single join with the table catalog_product_entity_decimal for the store id = 0.
Website attribute
If the scope of the attribute is website everything happens just like it does for the store view scope, because Magento creates a line in the attribute values table for each store view in the current website when saving the product.
If you want to try it use the attribute status in the examples above.
Flat Catalog
I promised earlier some explanations about "flat catalog".
For performance reasons Magneto introduced this feature (I don't remember the version).
Basically a cron runs (or you can run it by hand) and transforms the EAV approach for the products and categories into flat tables. One for each store view you have (except store id = 0).
This means one attribute will be transformed into one column in the new table. The new table is called catalog_product_flat_{store_view_id_here}.
This avoids the numerous left/inner joins when wanting the values for some attributes.
but again, for performance reasons, not all the attributes are added as columns in the flat tables (for products only. For categories all of them are added).
Only the attributes marked in the backend with Use in product listing are transformed into columns.
You can turn on/off this feature from System->Configuration->Catalog->Frontend->Use Flat Catalog Product (or Use Flat Catalog Category).
Even if turned on, the flat tables are used only in the frontend. The backend still uses the EAV approach.
Conclusion
My conclusion is that it is almost impossible to write your own queries to retrieve data directly from the DB. You should use the models and collections that magento provides. It saves a lot of mental health.
I hope I made things a little clearer for you.

Sql Result IN a Query

dont blame for the database design.I am not its database architect. I am the one who has to use it in current situation
I hope this will be understandable.
I have 3 tables containing following data with no foreign key relationship b/w them:
groups
groupId groupName
1 Admin
2 Editor
3 Subscriber
preveleges
groupId roles
1 1,2
2 2,3
3 1
roles
roleId roleTitle
1 add
2 edit
Query:
SELECT roles
from groups
LEFT JOIN preveleges ON (groups.groupId=preveleges.groupId)
returns specific result i.e roles.
Problem: I wanted to show roleTitle instead of roles in the above query.
I am confused how to relate table roles with this query and returns required result
I know it is feasible with coding but i want in SQL.Any suggestion will be appreciated.
SELECT g.groupName,
GROUP_CONCAT(r.roleTitle
ORDER BY FIND_IN_SET(r.roleId, p.roles))
AS RoleTitles
FROM groups AS g
LEFT JOIN preveleges AS p
ON g.groupId = p.groupId
LEFT JOIN roles AS r
ON FIND_IN_SET(r.roleId, p.roles)
GROUP BY g.groupName ;
Tested at: SQL-FIDDLE
I would change the data structure it self. Since It's not normalised, there are multiple elements in a single column.
But it is possible with SQL, if for some (valid) reason you can't change the DB.
A simple "static" solution:
SELECT REPLACE(REPLACE(roles, '1', 'add'), '2', 'edit') from groups
LEFT JOIN preveleges ON(groups.groupId=preveleges.groupId)
A more complex but still ugly solution:
CREATE FUNCTION ReplaceRoleIDWithName (#StringIds VARCHAR(50))
RETURNS VARCHAR(50)
AS
BEGIN
DECLARE #RoleNames VARCHAR(50)
SET #RoleNames = #StringIds
SELECT #RoleNames = REPLACE(#RoleNames, CAST(RoleId AS VARCHAR(50)), roleTitle)
FROM roles
RETURN #RoleNames
END
And then use the function in the query
SELECT ReplaceRoleIDWithName(roles) from groups
LEFT JOIN preveleges ON(groups.groupId=preveleges.groupId)
It is possible without function, but this is more readable. Made without editor so it's not tested in anyway.
You also tagged the question with PostgreSQL and it's actually quite easy with Postgres to work around this broken design:
SELECT grp.groupname, r.roletitle
FROM groups grp
join (
select groupid, cast(regexp_split_to_table(roles, ',') as integer) as role_id
from privileges
) as privs on privs.groupid = grp.groupid
join roles r on r.roleid = privs.role_id;
SQLFiddle: http://sqlfiddle.com/#!12/5e87b/1
(Note that I changed the incorrectly spelled name preveleges to the correct spelling privileges)
But you should really, really re-design your data model!
Fixing your design also enables you to define foreign key constraints and validate the input. In your current model, the application would probably break (just as my query would), if someone inserted the value 'one,two,three' into the roles table.
Edit
To complete the picture, using Postgres's array handling the above could be slightly simplified using a similar approach as MySQL's find_in_set()
select grp.groupname, r.roletitle
from groups grp
join privileges privs on grp.groupid = privs.groupid
join roles r on r.roleid::text = any (string_to_array(privs.roles, ','))
In both cases if all role titles should be shown as a comma separated list, the string_agg() function could be used (which is equivalent to MySQL's group_concat()
select grp.groupname, string_agg(r.roletitle, ',')
from groups grp
join privileges privs on grp.groupid = privs.groupid
join roles r on r.roleid::text = any (string_to_array(privs.roles, ','))
group by grp.groupname

SQL issue: one to many relationship and EAV model

Good evening guys,
I'm a newbie to web programming and I need your help to solve a problem inherent to SQL query.
The database engine I'm using is MySQL and I access it via PHP, here I'll explain a simplified version of my database, just to fix ideas.
Let's suppose to work with a database containing three tables: teams, teams_information, attributes. More precisely:
1) teams is a table containing some basic information about italian football teams (soccer, not american football :D), it is formed by three fields: 'id' (int, primary key), 'name' (varchar, team name), nickname (Varchar, team nickname);
2) attributes is a table containing a list of possible information about a football team, such as city (the city where team plays its home match), captain (team captain's fullname), f_number (number of fans) and so on. This table is formed by three fields: id (int, primary key), attribute_name (varchar, an identifier for the attribute), attribute_desc (text, an explanation of the meaning of attribute). Each record of this table represents a single possible attribute of a football team;
3) teams_information is a table where some information, about teams listed in team table, are available. This table contains three fields: id (int, primary key), team_id (int, a foreign key which identifies a team), attribute_id (int, a foreign key which identifies one of the attributes listed in attributes table), attribute_value (varchar, the value of the attribute). Each record represents a single attribute of a single team. In general, different teams will have a different number of information, so for some teams a large number of attributes will be available while for other teams only a small number of attributes will be available.
Note that relation between teams and teams_information is one to many and the same relation exists between attributes and teams_information
Well, given this model my purpose is to realize a grid (maybe with ExtJS 4.1) to show user the list of italian football team, each record of this grid will represent a single football team and will contain all possible attributes: some fields may be empty (because, for considered team, the correspondent attribute is unknown), while the others will contain the values stored in teams_information table (for the considered team).
According to the above grid's field are: id, team_name and a number of fields to represent all the different attributes listed in 'attributes' table.
My question is: can I realize such a grid by using a SINGLE SQL query (maybe a proper SELECT query, to fetch all data I need from database tables) ?
Can anyone suggest me how to write a similar query (if it exists) ?
Thanks in advance for helping me.
Regards.
Enrico.
The short answer to your question is no, there is no simple construct in MySQL to achieve the result set you are looking for.
But it is possible to carefully (painstakingly) craft such a query. Here is an example, I trust you will be able to decipher it. Basically, I'm using correlated subqueries in the select list, for each attribute I want returned.
SELECT t.id
, t.name
, t.nickname
, ( SELECT v1.attribute_value
FROM team_information v1
JOIN attributes a1
ON a1.id = v1.attribute_id AND a1.attribute_name = 'city'
WHERE v1.team_id = t.id ORDER BY 1 LIMIT 1
) AS city
, ( SELECT v2.attribute_value
FROM team_information v2 JOIN attributes a2
ON a2.id = v2.attribute_id AND a2.attribute_name = 'captain'
WHERE v2.team_id = t.id ORDER BY 1 LIMIT 1
) AS captain
, ( SELECT v3.attribute_value
FROM team_information v3 JOIN attributes a3
ON a3.id = v3.attribute_id AND a3.attribute_name = 'f_number'
WHERE v3.team_id = t.id ORDER BY 1 LIMIT 1
) AS f_number
FROM teams t
ORDER BY t.id
For 'multi-valued' attributes, you'd have to pull each instance of the attribute separately. (Use the LIMIT to specify whether you are retrieving the first one, the second one, etc.)
, ( SELECT v4.attribute_value
FROM team_information v4 JOIN attributes a4
ON a4.id = v4.attribute_id AND a4.attribute_name = 'nickname'
WHERE v4.team_id = t.id ORDER BY 1 LIMIT 0,1
) AS nickname_1st
, ( SELECT v5.attribute_value
FROM team_information v5 JOIN attributes a5
ON a5.id = v5.attribute_id AND a5.attribute_name = 'nickname'
WHERE v5.team_id = t.id ORDER BY 1 LIMIT 1,1
) AS nickname_2nd
, ( SELECT v6.attribute_value
FROM team_information v6 JOIN attributes a6
ON a6.id = v6.attribute_id AND a6.attribute_name = 'nickname'
WHERE v6.team_id = t.id ORDER BY 1 LIMIT 2,1
) AS nickname_3rd
I use nickname as an example here, because American soccer clubs frequently have more than one nickname, e.g. Chicago Fire Soccer Club has nicknames: 'The Fire', 'La Máquina Roja', 'Men in Red', 'CF97', et al.)
NOT AN ANSWER TO YOUR QUESTION, BUT ...
Have I mentioned numerous times before, how much I dislike working with EAV database implementations? What should IMO be a very simple query turns into an overly complicated beast of a potentially light dimming query.
Wouldn't it be much simpler to create a table where each "attribute" is a separate column? Then queries to return reasonable result sets would look more reasonable...
SELECT id, name, nickname, city, captain, f_number, ... FROM team
But what really makes me shudder is the prospect that some developer is going to decide that the LDQ should be "hidden" in the database as a view, to enable the "simpler" query.
If you go this route, PLEASE PLEASE PLEASE resist any urge you may have to store this query in the database as a view.
I'm going to take a slightly different route. Spencer's answer is fantastic, and it addresses the issue quite well, but there's still a large underlying problem.
The data that you are trying to display on the site is over-normalized in the database. I won't elaborate, since, again, Spencer's answer highlights the issue pretty well.
Rather, I'd like to recommend a solution that denormalizes the data a bit.
Convert all of your Team data into a single table with many columns. (If there is Player data that isn't covered in the question, that would be a second table, but I'll gloss over that for now.)
Sure, you'll have a whole bunch of columns, and a lot of the columns might be NULL for a lot of the rows. It's not normalized, and it's not pretty, but here's the huge advantage that you gain.
Your query becomes:
SELECT * FROM Teams
That's it. That gets displayed right to the website and you are done. You might have to go out of your way to realize this schema, but it would be totally worth the time investment.
I think what you're saying is that you want the rows in the attributes table to appear as columns in the result recordset. If this is correct, then then in SQL you would use PIVOT.
A quick search on SO seems to indicate that there is no PIVOT equivalent in MySql.
I wrote a simple PHP script to generalize spencer's idea to solve my issue.
Here's the code:
<?php
require_once('includes/db.config.php'); //this file performs connection to mysql
/*
* Following function requires a table name ($table)
* and a number of service fields ($num). Given those parameters
* it returns the number of table fields (excluding service fields).
*/
function get_fields_number($table,$num,$conn)
{
$query = "SELECT * FROM $table";
$result = mysql_query($query,$conn);
return mysql_num_fields($result)-$num; //remember there are $num service fields
}
/*
* Following function requires a table name ($table) and an array
* containing a list of service fields names. Given those parameters,
* it returns the list of field names. That list is contained within an array and
* service fields are excluded.
*/
function get_fields_name($table,$service,$conn)
{
$query = "SELECT * FROM $table";
$result = mysql_query($query,$conn);
$name = array(); //Array to be returned
for ($i=0;$i<mysql_num_fields($result);$i++)
{
if(!in_array(mysql_field_name($result,$i),$service))
{
//currently selected field is not a service field
$name[] = mysql_field_name($result,$i);
}
}
return $name;
}
//Below $conn is db connection created in 'db.config.php'
$query = "SELECT `name` FROM `detail_arg` WHERE visibility = 0";
$res = mysql_query($query,$conn);
if($res===false)
{
$err_msg = mysql_real_escape_string(mysql_error($conn));
echo "{success:false,data:'".$err_msg."'}";
die();
}
$arg = array(); //list of argument names
while($row = mysql_fetch_assoc($res))
{
$arg[] = $row['name'];
}
//Following function writes the select subquery which is
//necessary to build a column containing a single attribute.
function make_subquery($attribute) //$attribute contains attribute name
{
$query = "";
$query.="(SELECT incident_detail.arg_value ";
$query.="FROM incident_detail ";
$query.="INNER JOIN detail_arg ";
$query.="ON incident_detail.arg_id = detail_arg.id AND detail_arg.name='".$attribute."' ";
$query.="WHERE incident.id = incident_detail.incident_id) ";
$query.="AS $attribute";
return $query;
}
/*
echo make_subquery("date"); //debug code
*/
$subquery = array(); //list of subqueries
for($i=0;$i<count($arg);$i++)
{
$subquery[] = make_subquery($arg[$i]);
}
$query = "SELECT "; //final query containing subqueries
$fields = get_fields_name("incident",array("id","visibility"),$conn);
//list of 'incident' table's fields
for($i=0;$i<count($fields);$i++)
{
$query.="incident.".$fields[$i].", ";
}
//insert the subqueries
$sub = implode($subquery,", ");
$query .= $sub;
$query.=" FROM incident ORDER BY incident.id";
echo $query;
?>

Store procedure select all fields from One table using join

I am very frustrated from linq to sql when dealing with many to many relationship with the skip extension. It doesn't allow me to use joinned queries. Not sure it is the case for SQL server 2005 but I am currently using SQL Server 2000.
Now I consider to write a store procedure to fetch a table that is matched by two tables e.g. Album_Photo (Album->Album_Photo<-Photo) and Photo table and only want the Photos data so I match the Album's ID with Album_Photo and use that ID to match the photo. In the store procedure I am just fetch all the joinned data. After that in the linq to sql, I create a new Album object.
e.g.
var albums = (from r in result
where (modifier_id == r.ModifierID || user_id == r.UserID)
select new Album() {
Name = r.Name,
UserID = r.UserID,
ModifierID = r.ModifierID,
ID = r.ID,
DateCreated = r.DateCreated,
Description = r.Description,
Filename = r.Filename
}).AsQueryable();
I used the AsQueryable to get the result as a IQueryable rather than IEnumerable. Later I want to do something with the collection, it gives me this error:
System.InvalidOperationException: The query results cannot be enumerated more than once.
It sounds like you have a situation where the query has already executed by the time you are want to filter it later in your code.
Can you do something like...
var albums = (blah blah blah).AsQueryable().Where(filterClause) when you have enough info to process
what happens if you try albums.where(filter) later on in the code? Is this what you are trying?