Используйте LEFT JOIN
вместо INNER JOIN
:
SELECT c.id, c.name, c.unit, COUNT(p.category_id) as active_count
FROM `categories` c
LEFT JOIN `products` p
ON c.id = p.category_id AND p.is_active = 1
GROUP BY c.id;
Также важно перенести предикат p.is_active = 1
из предложения WHERE
в ON
, чтобы все записи таблицы categories
возвращаются запросом.
Если можно гарантировать, что нет никаких запятых в данных, то самый простой путь состоял бы в том, чтобы, вероятно, использовать String.split.
, Например:
String[] values = myString.Split(',');
myObject.StringField = values[0];
myObject.IntField = Int32.Parse(values[1]);
могут быть библиотеки, которыми Вы могли пользоваться к справке, но это, вероятно, так просто, как можно добраться. Просто удостоверьтесь, что у Вас не может быть запятых в данных, иначе необходимо будет проанализировать их лучше.
Я должен был использовать синтаксический анализатор CSV в.NET для проекта этим летом и обоснованный на текстовом Драйвере Microsoft Jet. Вы определяете папку с помощью строки подключения, затем запрашиваете файл с помощью оператора SQL Select. Можно определить сильные типы с помощью файла schema.ini. Я не сделал этого сначала, но тогда я получал плохие результаты, где тип данных не был сразу очевиден, таков как IP-адреса или запись как "XYQ 3.9 SP1".
Одно ограничение, с которым я столкнулся, - то, что это не может обработать имена столбцов выше 64 символов; это усекает. Это не должно быть проблемой, кроме я имел дело с очень плохо разработанными входными данными. Это возвращает ADO.NET DataSet.
Это было лучшим решением, которое я нашел. Я опасался бы прокручивать свой собственный синтаксический анализатор CSV, так как я, вероятно, пропущу некоторые случаи конца, и я не нашел никакие другие бесплатные пакеты парсинга CSV для.NET там.
РЕДАКТИРОВАНИЕ: Кроме того, может только быть один файл schema.ini на каталог, таким образом, я динамично добавил к нему для сильного ввода необходимых столбцов. Это только сильно-введет столбцы, определенные, и выведет для любого неуказанного поля. Я действительно ценил это, поскольку я имел дело с импортом жидких 70 + столбец CSV и не хотел определять каждый столбец, только неправильно себя ведущие.
Существует две статьи о CodeProject, которые обеспечивают код для решения, то, которое использует StreamReader и тот что данные CSV импорта использование текстовый Драйвер .
MicrosoftЯ скучал так, я изменил некоторый материал, который я записал. Это попытка инкапсулировать парсинг способом OO whle сокращающий объема повторений через файл, это только выполняет итерации однажды наверху foreach.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
// usage:
// note this wont run as getting streams is not Implemented
// but will get you started
CSVFileParser fileParser = new CSVFileParser();
// TO Do: configure fileparser
PersonParser personParser = new PersonParser(fileParser);
List<Person> persons = new List<Person>();
// if the file is large and there is a good way to limit
// without having to reparse the whole file you can use a
// linq query if you desire
foreach (Person person in personParser.GetPersons())
{
persons.Add(person);
}
// now we have a list of Person objects
}
}
public abstract class CSVParser
{
protected String[] deliniators = { "," };
protected internal IEnumerable<String[]> GetRecords()
{
Stream stream = GetStream();
StreamReader reader = new StreamReader(stream);
String[] aRecord;
while (!reader.EndOfStream)
{
aRecord = reader.ReadLine().Split(deliniators,
StringSplitOptions.None);
yield return aRecord;
}
}
protected abstract Stream GetStream();
}
public class CSVFileParser : CSVParser
{
// to do: add logic to get a stream from a file
protected override Stream GetStream()
{
throw new NotImplementedException();
}
}
public class CSVWebParser : CSVParser
{
// to do: add logic to get a stream from a web request
protected override Stream GetStream()
{
throw new NotImplementedException();
}
}
public class Person
{
public String Name { get; set; }
public String Address { get; set; }
public DateTime DOB { get; set; }
}
public class PersonParser
{
public PersonParser(CSVParser parser)
{
this.Parser = parser;
}
public CSVParser Parser { get; set; }
public IEnumerable<Person> GetPersons()
{
foreach (String[] record in this.Parser.GetRecords())
{
yield return new Person()
{
Name = record[0],
Address = record[1],
DOB = DateTime.Parse(record[2]),
};
}
}
}
}
Хороший простой способ сделать это состоит в том, чтобы открыть файл и считать каждую строку в массив, связанный список, data-structure-of-your-choice. Будьте осторожны относительно обработки первой строки все же.
Это может находиться вне Вашего понимания, но там, кажется, прямой способ получить доступ к ним также использование строка подключения .
, Почему бы не попытаться использовать Python вместо C# или VB? Это имеет хороший модуль CSV для импорта, который делает весь тяжелый подъем для Вас.
Brian дает хорошее решение для преобразования его к набору со строгим контролем типов.
большинство данных методов парсинга CSV не принимает во внимание поля выхода или часть другой тонкости файлов CSV (как обрезка полей). Вот код, который я лично использую. Это немного грубо вокруг краев и не имеет в значительной степени никакого сообщения об ошибке.
public static IList<IList<string>> Parse(string content)
{
IList<IList<string>> records = new List<IList<string>>();
StringReader stringReader = new StringReader(content);
bool inQoutedString = false;
IList<string> record = new List<string>();
StringBuilder fieldBuilder = new StringBuilder();
while (stringReader.Peek() != -1)
{
char readChar = (char)stringReader.Read();
if (readChar == '\n' || (readChar == '\r' && stringReader.Peek() == '\n'))
{
// If it's a \r\n combo consume the \n part and throw it away.
if (readChar == '\r')
{
stringReader.Read();
}
if (inQoutedString)
{
if (readChar == '\r')
{
fieldBuilder.Append('\r');
}
fieldBuilder.Append('\n');
}
else
{
record.Add(fieldBuilder.ToString().TrimEnd());
fieldBuilder = new StringBuilder();
records.Add(record);
record = new List<string>();
inQoutedString = false;
}
}
else if (fieldBuilder.Length == 0 && !inQoutedString)
{
if (char.IsWhiteSpace(readChar))
{
// Ignore leading whitespace
}
else if (readChar == '"')
{
inQoutedString = true;
}
else if (readChar == ',')
{
record.Add(fieldBuilder.ToString().TrimEnd());
fieldBuilder = new StringBuilder();
}
else
{
fieldBuilder.Append(readChar);
}
}
else if (readChar == ',')
{
if (inQoutedString)
{
fieldBuilder.Append(',');
}
else
{
record.Add(fieldBuilder.ToString().TrimEnd());
fieldBuilder = new StringBuilder();
}
}
else if (readChar == '"')
{
if (inQoutedString)
{
if (stringReader.Peek() == '"')
{
stringReader.Read();
fieldBuilder.Append('"');
}
else
{
inQoutedString = false;
}
}
else
{
fieldBuilder.Append(readChar);
}
}
else
{
fieldBuilder.Append(readChar);
}
}
record.Add(fieldBuilder.ToString().TrimEnd());
records.Add(record);
return records;
}
Примечание, что это не обрабатывает пограничный случай полей, не являющихся deliminated двойными кавычками, но meerley наличие заключенной в кавычки строки в нем. См. это сообщение некоторое время лучшего expanation, а также некоторых ссылок на некоторые надлежащие библиотеки.
Если Вы ожидаете, что довольно сложные сценарии для парсинга CSV, даже не продумывают прокрутки нашего собственного синтаксического анализатора . Существует много превосходных инструментов там, как FileHelpers, или даже от CodeProject.
точка, это - довольно типичная проблема, и Вы могли держать пари, что много из разработчиков программного обеспечения уже думали об и решили эту проблему.
Используйте Подключение OLEDB.
String sConnectionString = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=C:\\InputDirectory\\;Extended Properties='text;HDR=Yes;FMT=Delimited'";
OleDbConnection objConn = new OleDbConnection(sConnectionString);
objConn.Open();
DataTable dt = new DataTable();
OleDbCommand objCmdSelect = new OleDbCommand("SELECT * FROM file.csv", objConn);
OleDbDataAdapter objAdapter1 = new OleDbDataAdapter();
objAdapter1.SelectCommand = objCmdSelect;
objAdapter1.Fill(dt);
objConn.Close();
Я соглашаюсь с NotMyself. FileHelpers хорошо тестируется и обрабатывает все виды пограничных случаев, что необходимо будет в конечном счете иметь дело с тем, если Вы делаете это сами. Смотрите на то, что FileHelpers делает и только пишет Вашему собственному, если Вы абсолютно уверены, что любой (1) Вы никогда не должны будете обрабатывать пограничные случаи, которые FileHelpers делает, или (2) Вы любите писать этот вид материала и собираетесь быть очень счастливыми, когда необходимо проанализировать материал как это:
1, "счет", "Smith", "Супервизор", "Никакой Комментарий"
2, 'Drake', 'O'Malley', "Швейцар,
ой, я не заключаюсь в кавычки, и я нахожусь на новой строке!
TextFieldParser Microsoft стабилен и следует за RFC 4180 для файлов CSV. Не пугайтесь Microsoft.VisualBasic
пространство имен; это - стандартный компонент в Платформе.NET, просто добавьте ссылку на глобальное Microsoft.VisualBasic
блок.
Если Вы компилируете для Windows (в противоположность Моно) и не ожидаете иметь необходимость проанализировать "поврежденные" (non-RFC-compliant) файлы CSV, то это было бы очевидным выбором, поскольку это свободно, неограниченно, стабильно, и активно поддерживаемое, большинство которых не может быть сказано для FileHelpers.
См. также: Как к: Читайте Из Файлов Разделенного текста Запятой в Visual Basic для примера кода VB.