
- •Национальный исследовательский
- •Университет
- •В ы п у с к н а я р а б о т а
- •Введение
- •Глава 1 общие сведения об онтологиях и языках для спецификации онтологий
- •1.1. Содержание онтологии
- •1.2 Цели создания онтологий
- •1.3. Области применения онтологий
- •1.4. Формальная концептуализация и формальные онтологии
- •1.5. Формальная модель понятия и концептуальные языки
- •Глава 2 бинарная модель знаний
- •2.1. Синтаксис имен, используемых в бмз
- •2.2. Бинарная Модель Данных
- •2.2.1. Спецификация типов данных
- •2.2.2. Конструкторы типов данных
- •2.2.3. Спецификация функций
- •2.2.4. Спецификация структуры объектов
- •2.2.5. Синтаксис языка структурной спецификации
- •2.2.6. Атрибутные условия и интервальные ограничения
- •2.2.7. Структурные схемы
- •2.2.8. Представление данных в бмд
- •2.2.9. Логические предложения.
- •Глава 3 язык запросов для бинарной модели данных
- •3.1. Примеры запросов
- •3.2. Описание запросов
- •3.3. Описание алгоритма трансляции.
- •3.4. Примеры работы транслятора.
- •Глава 4 описание и использование программы, реализуюшей транслятор
- •4.1. Описание интерфейса программы.
- •4.2. Задание схемы
- •4.3. Использование транслятора в программном коде.
- •4.4. Программа с подключенной базой данных.
- •Приложение
- •Код программы Файл Onthology.Cs
- •Файл Translator.Cs
- •Заключение
- •Литература
- •Содержание
Файл Translator.Cs
using System;
using System.Data;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Запросы
{
class TranslatorException : Exception
{
public TranslatorException() { }
public TranslatorException(string message) : base(message) { }
public TranslatorException(string message, Exception inner) : base(message, inner) { }
}
/// <summary>
/// Транслирует язык запросов на язык SQL
/// </summary>
class Translator
{
/// <summary>
/// Класс, описывающий переменную, ее тип и известные значения.
/// </summary>
class QueryVariable
{
static public OnthologyScheme scheme;
string name;
OnthologyClass oclass;
List<string> neededAttributes;
List<string> complexAttributes;
List<string> simpleAttributes;
List<string> simpleAttributeOperators;
List<string> simpleAttributeValues;
List<string> classAttributes;
List<QueryVariable> classVariables;
public QueryVariable(string _name, string className)
: this(_name)
{
AddClass(className);
}
public QueryVariable(QueryVariable parentVar, string _name, string className)
: this(_name)
{
AddClassOnAttribute(parentVar, className);
}
public QueryVariable(string _name)
{
name = _name;
oclass = null;
simpleAttributes = new List<string>();
neededAttributes = new List<string>();
simpleAttributeValues = new List<string>();
simpleAttributeOperators = new List<string>();
complexAttributes = new List<string>();
classAttributes = new List<string>();
classVariables = new List<QueryVariable>();
}
public void AddClass(string className)
{
OnthologyClass oc = scheme.Classes.Find(c => c.Name == className);
if (oc == null)
oc = scheme.Relations.Find(c => c.Name == className);
if (oc == null)
throw new TranslatorException("Переменная " + Name + " имеет неопределенный в схеме класс: " + className);
if (oclass != null && oclass != oc)
throw new TranslatorException("Неоднозначный тип у переменной " + Name + ". Возможные значения типов:" + className + "," + oclass.Name);
oclass = oc;
}
public void AddClassOnAttribute(QueryVariable parentVar, string attributeClassName)
{
if (parentVar.Class is OnthologyRelation)
{
OnthologyRelation ontRel = (OnthologyRelation)parentVar.Class;
if (ontRel.Left.Name.ToUpper() == attributeClassName.ToUpper())
oclass = ontRel.Left;
if (ontRel.Right.Name.ToUpper() == attributeClassName.ToUpper())
oclass = ontRel.Right;
}
else
{
oclass = parentVar.Class.ClassAttributes.Find(c => c.Name.ToUpper() == attributeClassName.ToUpper()).Type;
}
}
public void AddNeededAttribute(string attr)
{
neededAttributes.Add(attr);
}
public void AddComplexAttribute(string attr)
{
complexAttributes.Add(attr);
}
public void AddSimpleAttribute(string attr, string attrOperator, string value)
{
simpleAttributes.Add(attr);
simpleAttributeOperators.Add(attrOperator);
simpleAttributeValues.Add(value);
}
public void AddClassAttribute(string attr, QueryVariable qv)
{
classAttributes.Add(attr);
classVariables.Add(qv);
}
public void DefineClass()
{
if (oclass == null)
for (int i = 0; i < scheme.Classes.Count; i++)
{
OnthologyClass oc = scheme.Classes[i];
if (attrIsInColumns(oc, neededAttributes) && attrIsInColumns(oc, simpleAttributes))
{
oclass = oc;
return;
}
}
}
bool attrIsInColumns(OnthologyClass Class, List<string> QueryAttributes)
{
bool allAttrsInTable = true;
foreach (string queryAttrName in QueryAttributes)
{
bool attrIsInColumns = false;
foreach (OnthologyAttribute<string> classAttr in Class.SimpleAttributes)
{
if (queryAttrName == classAttr.Name)
{
attrIsInColumns = true;
break;
}
}
if (!attrIsInColumns)
{
allAttrsInTable = false;
break;
}
}
return allAttrsInTable;
}
public string Name
{
get
{
return name;
}
}
public OnthologyClass Class
{
get
{
return oclass;
}
}
public List<string> NeededAttributes
{
get
{
return neededAttributes;
}
}
public List<string> SimpleAttributes
{
get
{
return simpleAttributes;
}
}
public List<string> SimpleAttributeOperators
{
get
{
return simpleAttributeOperators;
}
}
public List<string> SimpleAttributeValues
{
get
{
return simpleAttributeValues;
}
}
public List<string> ComplexAttributes
{
get
{
return complexAttributes;
}
}
public List<string> ClassAttributes
{
get
{
return classAttributes;
}
}
public List<QueryVariable> ClassVariables
{
get
{
return classVariables;
}
}
}
/// <summary>
/// Класс, описывающий отношение.
/// </summary>
class Relation
{
public Relation()
{ }
public Relation(QueryVariable q1, QueryVariable q2, QueryVariable q3)
{
Left = q1;
RelVar = q2;
Right = q3;
}
public QueryVariable Left
{ get; set; }
public QueryVariable RelVar
{ get; set; }
public QueryVariable Right
{ get; set; }
public QueryVariable this[int i]
{
get
{
if (i == 0)
return Left;
if (i == 1)
return RelVar;
return Right;
}
}
}
class AttrPair
{
public QueryVariable qv1;
public string attr1;
public string attrOperator;
public QueryVariable qv2;
public string attr2;
public AttrPair(QueryVariable q1, string a1, string oper, QueryVariable q2, string a2)
{
qv1 = q1;
attr1 = a1;
attrOperator = oper;
qv2 = q2;
attr2 = a2;
}
}
static string[] operators = new string[] { "<=",">=","=","LIKE"};
static string[] aggregateFunctions = new string[] {"AVG","SUM","COUNT","MAX","MIN"};
#region Переменные
string query;
int artificialVarsCount;
string SQLquery;
string select;
string[] selectParts;
string condition;
List<QueryVariable> goalVariables;
string aggregateFunction;
List<QueryVariable> variables;
List<Relation> RelationVars;
List<AttrPair> AttrPairs;
OnthologyScheme scheme;
#endregion
#region Конструктор
public Translator(OnthologyScheme _scheme)
{
scheme = _scheme;
QueryVariable.scheme = scheme;
}
public string translate(string _query)
{
query = _query.Trim().Replace("\r\n", "");
goalVariables = new List<QueryVariable>();
variables = new List<QueryVariable>();
RelationVars = new List<Relation>();
AttrPairs = new List<AttrPair>();
artificialVarsCount = 0;
if (query == "")
{
throw new TranslatorException("Запрос пуст");
}
else if (query[0] != '?')
{
throw new TranslatorException("В начале запроса должен стоять вопросительный знак");
}
else
{
query = query.Substring(1, query.Length - 1);
divideQuery(query);
GoalProcessing();
ConditionsProcessing();
checkVariablesClass();
removeUselessVariables();
return CreateSQLQuery(query);
}
}
#endregion
void divideQuery(string query)
{
int hyphenPosition = 0;
bool hyphenIsInQuery = false;
for (int i = 0; i < query.Length; i++)
{
if (query[i] == '-')
{
hyphenPosition = i;
hyphenIsInQuery = true;
break;
}
}
if (!hyphenIsInQuery)
throw new TranslatorException("Отсутвует знак /'-/'");
if (query.Contains(" __"))
throw new TranslatorException("Нельзя использовать символы \"__\" в начале слова");
select = query.Substring(0,hyphenPosition).Trim();
condition = query.Substring(hyphenPosition + 1).Trim();
if (select == "")
throw new TranslatorException("Отсутсвует целевая переменная(выражение перед знаком /'-/')");
if (condition == "")
throw new TranslatorException("Отсутсвуют условия (выражения после знака /'-/')");
select = select.Trim();
condition = condition.Trim();
}
void GoalProcessing()
{
selectParts = select.Split(',');
QueryVariable qv = new QueryVariable("");
bool aggrFuncIsInSelect = false;
for (int i = 0; i < selectParts.Length; i++)
{
string s = selectParts[i].Trim();
if (s.Trim() == "")
{
if (i == 0)
throw new TranslatorException("Лишняя запятая после первой цели запроса " + select);
else
throw new TranslatorException("Лишняя запятая после цели " + selectParts[i - 1]);
}
int bracketPostion = s.IndexOf("(");
if (bracketPostion != -1)
{
if (!s.EndsWith(")"))
throw new TranslatorException("Незакрытая скобка в цели запроса " + s);
aggregateFunction = s.Substring(0, bracketPostion);
s = s.Substring(bracketPostion+1, s.Length - bracketPostion -2);
if (!aggregateFunctions.Contains(aggregateFunction))
throw new TranslatorException("Неизвестная функция \"" + aggregateFunction + "\" в цели запроса " + s);
aggrFuncIsInSelect = true;
}
string varName;
string attrName;
string[] goalVarParts = s.Split('.');
int lastDot = s.LastIndexOf('.');
if (goalVarParts.Length >= 3)
{
varName = "__" + artificialVarsCount;
artificialVarsCount++;
condition += ";" + s.Substring(0, lastDot) + "=" + varName;
s = varName + "." + goalVarParts[goalVarParts.Length - 1];
}
if (s.IndexOf('.') == -1)
{
varName = s;
attrName = "id";
}
else
{
varName = s.Split('.')[0];
attrName = s.Split('.')[1];
}
if (qv.Name != varName)
{
if (qv.Name != "")
{
goalVariables.Add(qv);
variables.Add(qv);
}
qv = new QueryVariable(varName);
qv.AddNeededAttribute(attrName);
}
else
{
qv.AddNeededAttribute(attrName);
}
}
goalVariables.Add(qv);
variables.Add(qv);
if (aggrFuncIsInSelect && selectParts.Length >= 2)
throw new TranslatorException("В запросе можно использовать только одну цель, если используется аггрегатная функция");
}
void ConditionsProcessing()
{
List<string> conjParts = new List<string>();
bool inBrackets = false;
string conjuctS = "";
int conjuctNumber = 0;
for (int i = 0; i < condition.Length; i++)
{
if (inBrackets && condition[i] == '(')
throw new TranslatorException("Лишняя открывающяя скобка на "+ i +" символе");
if (!inBrackets && condition[i] == ')')
throw new TranslatorException("Лишняя закрывающяя скобка на " + i + " символе");
if (condition[i] == '(')
inBrackets = true;
if (inBrackets && condition[i] == ')')
inBrackets = false;
if (!inBrackets && condition[i] ==';')
{
conjuctNumber++;
if (conjuctS.Trim() == "")
throw new TranslatorException("Конъюнктивное выражение под номером " + conjuctNumber + " пусто ( возможно лишний символ \";\")");
conjParts.Add(conjuctS.Trim());
conjuctS = "";
continue;
}
conjuctS += condition[i];
}
if (conjuctS.Trim() == "")
throw new TranslatorException("Последнее конъюнктивное выражение пусто ( возможно лишний символ \";\")");
conjParts.Add(conjuctS.Trim());
int k;
string varName;
string attrName;
string className;
List<string> conditionParts = new List<string>();
for (int i = 0; i < conjParts.Count; i++)
{
string s = conjParts[i].Trim();
#region Обработка типа
int inPosition = s.IndexOf(" IN ");
if (inPosition >= 0)
{
string typeS = s;
varName = typeS.Substring(0, inPosition).Trim();
int bracketPosition = s.IndexOf("(");
if (bracketPosition >= 0)
{
if (bracketPosition <= inPosition)
throw new TranslatorException("При использовании ключевого слова \"IN\" скобка должна стоять после имени класса");
if (!s.EndsWith(")"))
throw new TranslatorException("Отсутствует закрывающяя скобка");
typeS = s.Substring(0, bracketPosition).Trim();
string bracketS = s.Substring(bracketPosition+1,s.Length - bracketPosition - 2).Trim();
if (bracketS == "")
throw new TranslatorException("Пустое выражение внутри скобок в выражении " + s);
string[] sInBrackets = bracketS.Split(';');
conjParts.RemoveAt(i);
for (int j = sInBrackets.Length - 1; j >= 0; j--)
{
conjParts.Insert(i, varName + "." + sInBrackets[j]);
}
i--;
}
className = typeS.Substring(inPosition + 4).Trim();
k = scheme.Classes.FindIndex(cl => cl.Name == className);
if (k == -1)
{
k = scheme.Relations.FindIndex(rel => rel.Name == className);
if (k == -1)
throw new TranslatorException("Неизвестный класс: " + className + " в условии \"" + s + "\"");
}
k = variables.FindIndex(v => v.Name == varName);
if (k == -1)
variables.Add(new QueryVariable(varName,className));
else
variables[k].AddClass(className);
continue;
}
#endregion
#region Обработка отношения
int openBracketPosition = s.IndexOf('(');
if (openBracketPosition == 0)
{
if (!s.EndsWith(")"))
{
throw new TranslatorException("Отсутствует закрывающяя скобка");
}
string[] RelationParts = s.Substring(1, s.Length - 2).Split(' ');
for (int j = 0; j < RelationParts.Length; j++)
{
RelationParts[i] = RelationParts[i].Trim();
}
if (RelationParts.Length != 4 && RelationParts.Length != 3)
throw new TranslatorException("Отношение должно состоять из 4 слов:(X RelationName L Y) или из 3: (X RelationName Y)");
QueryVariable relVar;
QueryVariable leftVar;
QueryVariable rightVar;
if (RelationParts.Length == 3)
{
varName = "__" + artificialVarsCount;
artificialVarsCount++;
}
else
{
varName = RelationParts[2].Trim();
}
className = RelationParts[1].Trim();
int relIndex = scheme.Relations.FindIndex(rel => rel.Name == className);
if (relIndex == -1)
throw new TranslatorException("Переменная отношения" + varName + " относится к неизвестному отношению " + className);
string leftClassName = scheme.Relations[relIndex].Left.Name;
string rightClassName = scheme.Relations[relIndex].Right.Name;
#region Переменная отношения
k = variables.FindIndex(v => v.Name == varName);
if (k >= 0)
{
relVar = variables[k];
relVar.AddClass(className);
}
else
{
relVar = new QueryVariable(varName, className);
variables.Add(relVar);
}
#endregion
#region Левая переменная отношения
varName = RelationParts[0];
k = variables.FindIndex(v => v.Name == varName);
if (k >= 0)
{
leftVar = variables[k];
leftVar.AddClass(leftClassName);
}
else
{
leftVar = new QueryVariable(varName, leftClassName);
variables.Add(leftVar);
}
#endregion
#region Правая переменная отношения
varName = RelationParts.Last();
k = variables.FindIndex(v => v.Name == varName);
if (k >= 0)
{
rightVar = variables[k];
rightVar.AddClass(rightClassName);
}
else
{
rightVar = new QueryVariable(varName, rightClassName);
variables.Add(rightVar);
}
#endregion
relVar.AddClassAttribute(leftClassName, leftVar);
relVar.AddClassAttribute(rightClassName, rightVar);
Relation relation = new Relation(leftVar, relVar, rightVar);
RelationVars.Add(relation);
continue;
}
else if(openBracketPosition != -1)
{
int closeBracketPosition = s.IndexOf(')');
if (openBracketPosition > closeBracketPosition)
throw new TranslatorException("Лишняя закрывающяя скобка в выражении " + s);
varName = s.Substring(openBracketPosition + 1, closeBracketPosition - openBracketPosition - 1);
string relType = s.Substring(0, openBracketPosition);
string rest = s.Substring(closeBracketPosition + 1);
if (rest.IndexOf(')') != -1)
throw new TranslatorException("Лишняя закрывающяя скобка в выражении " + s);
int relIndex = scheme.Relations.FindIndex(rel => rel.Name == relType);
if (relIndex == -1)
throw new TranslatorException("Неизвестное отношение \"" +relType + "\"в выражении "+s);
QueryVariable leftVar;
QueryVariable rightVar;
int varIndex = variables.FindIndex(var => var.Name == varName);
if (varIndex >= 0)
{
leftVar = variables[varIndex];
leftVar.AddClass(scheme.Relations[relIndex].Left.Name);
}
else
{
leftVar = new QueryVariable(varName, scheme.Relations[relIndex].Left.Name);
variables.Add(leftVar);
}
string artifName = "__" + artificialVarsCount;
artificialVarsCount++;
rightVar = new QueryVariable(artifName, scheme.Relations[relIndex].Right.Name);
variables.Add(rightVar);
s = artifName + rest;
artifName = "__" + artificialVarsCount;
artificialVarsCount++;
variables.Add(new QueryVariable(artifName, scheme.Relations[relIndex].Name));
variables.Last().AddClassAttribute(leftVar.Class.Name, leftVar);
variables.Last().AddClassAttribute(rightVar.Class.Name, rightVar);
RelationVars.Add(new Relation(leftVar,variables.Last(),rightVar));
}
#endregion
conditionParts.Add(s);
}
for (int i = 0; i < conditionParts.Count; i++)
{
string s = conditionParts[i].Trim();
#region Обработка условия
#region Проверка на присутствие операторов
bool operatorIsIn = false;
string operatorStr = "";
string cumulativeStr = "";
for (int j = 0; j < s.Length; j++)
{
if (j != (s.Length - 1) && s[j] == '<' && s[j + 1] == '=')
{
if (operatorIsIn)
throw new TranslatorException("В выражении " + s + " несколько операторов");
operatorIsIn = true;
operatorStr = "<=";
j += 2;
}
if (j != (s.Length - 1) && s[j] == '>' && s[j + 1] == '=')
{
if (operatorIsIn)
throw new TranslatorException("В выражении " + s + " несколько операторов");
operatorIsIn = true;
operatorStr = ">=";
j += 2;
}
if (j != (s.Length - 1) && s[j] == '<' && s[j + 1] != '=')
{
if (operatorIsIn)
throw new TranslatorException("В выражении " + s + " несколько операторов");
operatorIsIn = true;
operatorStr = "<";
j++;
}
if (j != (s.Length - 1) && s[j] == '>' && s[j + 1] != '=')
{
if (operatorIsIn)
throw new TranslatorException("В выражении " + s + " несколько операторов");
operatorIsIn = true;
operatorStr = ">";
j++;
}
if (j != (s.Length-1) && s[j] == '=')
{
if (operatorIsIn)
throw new TranslatorException("В выражении " + s + " несколько операторов");
operatorIsIn = true;
operatorStr = "=";
j++;
}
cumulativeStr += s[j];
}
if (!operatorIsIn)
throw new TranslatorException("В выражении " + s + " отсутствует оператор");
#endregion
string[] condparts = s.Split(operatorStr.ToArray(),StringSplitOptions.RemoveEmptyEntries);
#region Обработка короткой левой части
// if (condparts.Length > 2) Не может такого быть - ошибка, когда больше двух обрабатывается раньше
// throw new TranslatorException("В условии много операторов");
string[] leftParts = condparts[0].Split('.');
if (leftParts.Length > 2) // Из одного условия делается несколько с использованием новых переменных
{
varName = leftParts[0].Trim();
string artVarName = "__" + artificialVarsCount;
conditionParts.RemoveAt(i--);
string DividedConj;
for (int j = 1; j < leftParts.Length - 1; j++)
{
artificialVarsCount++;
DividedConj = varName + "." + leftParts[j] + "=" + artVarName;
conditionParts.Insert(i + j , DividedConj);
varName = artVarName;
artVarName = "__" + artificialVarsCount;
}
DividedConj = varName + "." + leftParts.Last() + operatorStr + condparts[1];
conditionParts.Insert(i + leftParts.Length - 1, DividedConj);
continue;
}
#endregion
#region Обработка короткой правой части
string[] rightParts = condparts[1].Split('.');
if (rightParts.Length >= 2) // Из одного условия делается несколько с использованием новых переменных
{
varName = rightParts[0].Trim();
if (scheme.Classes.FindIndex(cl => cl.Name == varName) >= 0 ||
scheme.Relations.FindIndex(rel => rel.Name == varName) >= 0)
{
string artifName = "__" + artificialVarsCount;
artificialVarsCount++;
variables.Add(new QueryVariable(artifName, varName));
varName = artifName;
}
if (rightParts.Length > 2)
{
string artVarName = "__" + artificialVarsCount;
conditionParts.RemoveAt(i--);
string DividedConj;
for (int j = 1; j < rightParts.Length - 1; j++)
{
artificialVarsCount++;
DividedConj = varName + "." + rightParts[j] + "=" + artVarName;
conditionParts.Insert(i + j, DividedConj);
varName = artVarName;
artVarName = "__" + artificialVarsCount;
}
DividedConj = leftParts[0];
for (int j = 1; j < leftParts.Length; j++)
{
DividedConj += "." + leftParts[j];
}
DividedConj += operatorStr + varName + "." + rightParts.Last();
conditionParts.Insert(i + rightParts.Length - 1, DividedConj);
continue;
}
}
#endregion
varName = leftParts[0].Trim();
attrName = leftParts[1].Trim();
// Если не содержит точку, значит - известное значение
if (rightParts.Length <= 2)
{
k = variables.FindIndex(v => v.Name == varName);
if (k == -1)
throw new TranslatorException("Переменная " + varName + " неизвестного типа");
if (variables[k].Class.isSimpleAttribute(attrName))
{
if (rightParts.Length == 2)
{
QueryVariable rightvar;
int l = variables.FindIndex(v => v.Name == rightParts[0]);
rightvar = variables.ElementAt(l);
variables[k].AddComplexAttribute(attrName);
rightvar.AddComplexAttribute(rightParts[1]);
AttrPairs.Add(new AttrPair(variables[k],attrName,operatorStr,rightvar,rightParts[1]));
}
else
{
string value = condparts[1].Trim();
variables[k].AddSimpleAttribute(attrName, operatorStr, value);
}
}
else if (variables[k].Class.isClassAttribute(attrName))
{
if (operatorStr != "=")
throw new TranslatorException("Ошибка записи в выражении" + s + ". В аттрибутах, где используются суррогаты можно использовать только оператор \"=\"");
string newvarName = condparts[1].Trim();
QueryVariable newvar;
int l = variables.FindIndex(v => v.Name == newvarName);
if (l >= 0)
{
newvar = variables.ElementAt(l);
newvar.AddClassOnAttribute(variables[k], attrName);
}
else
{
newvar = new QueryVariable(variables[k], newvarName, attrName);
variables.Add(newvar);
}
variables[k].AddClassAttribute(attrName, newvar);
}
else
throw new TranslatorException("Переменная " + variables[k].Name + " относится к классу " + variables[k].Class.Name +
", но в этом классе не содержится аттрибут \"" + attrName + "\"");
continue;
}
#endregion
}
}
void checkVariablesClass()
{
foreach (QueryVariable qv in variables)
{
if (qv.Class == null)
throw new TranslatorException("Переменная " + qv.Name + " неизвестного типа");
foreach(string classAttr in qv.ClassAttributes)
{
if (!qv.Class.isClassAttribute(classAttr))
throw new TranslatorException("Переменная " + qv.Name + " относится к классу " + qv.Class +
", но в этом классе не содержится аттрибут \"" + classAttr + "\"");
}
foreach(string classAttr in qv.ClassAttributes)
{
if (!qv.Class.isClassAttribute(classAttr))
throw new TranslatorException("Переменная " + qv.Name + " относится к классу " + qv.Class +
", но в этом классе не содержится аттрибут \"" + classAttr + "\"");
}
}
}
void removeUselessVariables()
{
List<QueryVariable> necessaryVars = new List<QueryVariable>(goalVariables);
List<QueryVariable> uselessVars = (new List<QueryVariable>(variables)).Except(goalVariables).ToList();
for (int i = 0; i < necessaryVars.Count; i++)
{
if (uselessVars.Count == 0)
break;
int j = AttrPairs.FindIndex(ap => necessaryVars[i].Name == ap.qv1.Name);
if (j != -1)
{
if (!necessaryVars.Contains(AttrPairs[j].qv2))
necessaryVars.Add(AttrPairs[j].qv2);
uselessVars.Remove(AttrPairs[j].qv2);
}
j = AttrPairs.FindIndex(ap => necessaryVars[i].Name == ap.qv2.Name);
if (j != -1)
{
if (!necessaryVars.Contains(AttrPairs[j].qv1))
necessaryVars.Add(AttrPairs[j].qv1);
uselessVars.Remove(AttrPairs[j].qv1);
}
for (j = 0; j < uselessVars.Count; j++)
{
if (necessaryVars[i].ClassVariables.Contains(uselessVars[j]) ||
uselessVars[j].ClassVariables.Contains(necessaryVars[i]))
{
necessaryVars.Add(uselessVars[j]);
uselessVars.Remove(uselessVars[j]);
j--;
}
}
}
variables = new List<QueryVariable>(necessaryVars);
}
string EscapeKeyword(string word)
{
string wordInUpper = word.ToUpper();
if (wordInUpper == "GROUP")
return "[" + word +"]";
return word;
}
string CreateSQLSubQuery(QueryVariable qv)
{
string subquery = "SELECT id";
List<string> requiredAttributes;
if (goalVariables.Contains(qv))
{
requiredAttributes = qv.ClassAttributes.Union(qv.NeededAttributes).ToList();
}
else
requiredAttributes = qv.ClassAttributes;
requiredAttributes = requiredAttributes.Union(qv.ComplexAttributes).Distinct().ToList();
for (int i = 0; i < requiredAttributes.Count; i++)
{
if (requiredAttributes[i] != "id")
subquery += ", " + EscapeKeyword(requiredAttributes[i]);
}
subquery += " FROM " + EscapeKeyword(qv.Class.Name);
if (qv.SimpleAttributes.Count != 0)
{
subquery += " WHERE ";
subquery += qv.SimpleAttributes[0] + qv.SimpleAttributeOperators[0] + qv.SimpleAttributeValues[0];
for (int i = 1; i < qv.SimpleAttributes.Count; i++)
{
subquery += " AND " + qv.SimpleAttributes[i] + qv.SimpleAttributeOperators[i] + qv.SimpleAttributeValues[i];
}
}
return subquery;
}
#region SQLQuery VERSION ACTIVE
string CreateSQLQuery(string query)
{
if (goalVariables.Count == 0)
throw new TranslatorException("Не задана целевая переменая");
SQLquery = "SELECT DISTINCT ";
bool firstVariableProceeded = false;
for (int i = 0; i < goalVariables.Count; i++)
{
QueryVariable goalVar = goalVariables[i];
if (goalVar.Class == null)
throw new TranslatorException("Переменная " + goalVar.Name + " неизвестного типа");
for (int j = 0; j < goalVar.NeededAttributes.Count; j++)
{
if (!firstVariableProceeded)
firstVariableProceeded = true;
else
SQLquery += ", ";
string neededAttrSQL = EscapeKeyword(goalVar.Name) + "." + EscapeKeyword(goalVar.NeededAttributes[j]);
if (aggregateFunction != null)
neededAttrSQL = aggregateFunction + "( " + neededAttrSQL + ")";
SQLquery += neededAttrSQL;
}
}
SQLquery += Environment.NewLine;
SQLquery += "FROM " + "(" + CreateSQLSubQuery(variables[0]) + ") AS " + variables[0].Name;
for (int i = 1; i < variables.Count; i++)
SQLquery += Environment.NewLine + "CROSS JOIN " + "(" + CreateSQLSubQuery(variables[i]) + ") AS " + variables[i].Name;
if (variables.Count > 1)
{
SQLquery += Environment.NewLine + "WHERE ";
firstVariableProceeded = false;
for (int i = 0; i < variables.Count; i++)
{
for (int j = 0; j < variables[i].ClassAttributes.Count; j++)
{
if (!firstVariableProceeded)
firstVariableProceeded = true;
else
SQLquery += " AND ";
SQLquery += variables[i].Name + "." + EscapeKeyword(variables[i].ClassAttributes[j]) +
" = " + EscapeKeyword(variables[i].ClassVariables[j].Name) + ".id";
}
}
for (int i = 0; i < AttrPairs.Count; i++)
{
SQLquery += " AND "+ AttrPairs[i].qv1.Name + "." + AttrPairs[i].attr1 + AttrPairs[i].attrOperator + AttrPairs[i].qv2.Name + "." + AttrPairs[i].attr2;
}
}
return SQLquery;
}
#endregion
#region Свойства
public string Query
{
get
{
return query;
}
}
public string SQLQuery
{
get
{
return SQLquery;
}
}
public string Select
{
get
{
return select;
}
}
public string Condition
{
get
{
return condition;
}
}
#endregion
}
}