none
Получить уникальные значения из списка RRS feed

  • Вопрос

  • Как програмно получить уникальные значения из списка?

    Например:

    Америка 100
    Россия 50
    Африка 10
    Аргентина 57
    Америка 16
    Россия 32
    Африка 160

    Надо получить Америка, Россия, Африка, Аргентина. Элементов в списке может быть очень много (4000-10000).

    И еще один вопрос, можно ли сразу получить суммы?

    Нашел такой способ:

    DataTable dtTable = answer_list.GetItems(spquery).GetDataTable();
    DataView dvView = new DataView(dtTable);
    DataTable countryTable = dvView.ToTable(true, "country");
    Но он не очень быстрый, и на большом количестве элементов медленно работает. А подсчет сумм вообще организовал в простом foreach, что тоже работает не очень шустро.

Ответы

  • Добрый день, вы можете использовать механизм определения distinct значений, которй используется "вьюхами" списка (при фильтрации колонки - filter.aspx). Покопавшись глубже выяснили что быстро получить Distinct Values  можно следующим образом (даже для списков в 20+ тыс записей):

                var request = (HttpWebRequest)WebRequest.Create(requestUrl);
                request.UseDefaultCredentials = true;
                var response = request.GetResponse();

    где requestUrl следующий:

        <add key="ColumnFilterUrl" value="/_layouts/filter.aspx?ListId={0}&amp;FieldInternalName={1}&amp;ViewId={2}&amp;Filter=1"/>

    Просто нужно подставить туда:

    1. Id списка,
    2. Внутреннее имя колонки,
    3. ID вьюхи

    Если не знаете что туда написать - просто в браузере в представлении списка отфильтруйте список и посмотрите на URL после postback'a.

    Такой способ в разы быстрее чем SPQuery или Linq.


    LinkedIn Profile

    • Изменено HeToC 1 июня 2012 г. 10:49
    • Предложено в качестве ответа HeToC 2 июня 2012 г. 8:59
    • Помечено в качестве ответа Roman Zhukov 29 июня 2012 г. 12:04
    1 июня 2012 г. 10:48
  • У вашего Lookup поля стоит наверное AllowMultipleValues, верно ?

    Тогда выбранные значения хранятся в таблице dbo.AllUserDataJunctions или dbo.UserDataJunctions.

    Смотрите мой ответ в соседней теме.

    ===============================================
    SELECT
        d.nvarchar3 AS vn
        , u.UserName AS un
        , j.tp_ID AS cid
    FROM UserData d --build in SQL data view that filters deleted items
        LEFT OUTER JOIN UserDataJunctions j ON d.tp_LeafName = j.tp_LeafName -- <-- this is the id for the multiple records that you picked
            AND d.tp_DirName = j.tp_DirName -- <-- this and the leafname are needed to make the match and pull the multiple values
        INNER JOIN vCID c ON j.tp_ID = c.cid --my custom view for id listing - not my real view names
        INNER JOIN vGU u ON d.nvarchar3 = u.vn --my custom view to pull user data - not my real view names :)
    WHERE
        d.tp_ListID = 'yourlonglistidhere'


    LinkedIn Profile

    • Изменено HeToC 5 июня 2012 г. 9:39
    • Помечено в качестве ответа Roman Zhukov 29 июня 2012 г. 12:05

Все ответы

  • К сожалению, SharePoint не дает возможностей выполнения таких операций в виде запросов. Единственный способ - загрузить в память и в памяти проводить операции. Один из таких способов приведенн в вашем примере.

    Иначе могут работать механизмы Linq. Distinct и Sum могут дать вам иную скорость, однако, возможно, может получиться и медленее.


    SharePoint MCPD, MCITP. Высказанное мною здесь - мои личные взгляды, а не позиции корпорации Microsoft. Вся информация предоставляется "как есть" без каких-либо гарантий.

    Модератор
  • В дополнение того, что сказал Игорь, посмотрите примеры тут What is the best way to retrieve distinct / unique values using SPQuery?

    Dmitry

    Lightning Tools LogoLightning Tools Check out our SharePoint tools and web parts | Lightning Tools Blog

    1 июня 2012 г. 10:34
    Отвечающий
  • Добрый день, вы можете использовать механизм определения distinct значений, которй используется "вьюхами" списка (при фильтрации колонки - filter.aspx). Покопавшись глубже выяснили что быстро получить Distinct Values  можно следующим образом (даже для списков в 20+ тыс записей):

                var request = (HttpWebRequest)WebRequest.Create(requestUrl);
                request.UseDefaultCredentials = true;
                var response = request.GetResponse();

    где requestUrl следующий:

        <add key="ColumnFilterUrl" value="/_layouts/filter.aspx?ListId={0}&amp;FieldInternalName={1}&amp;ViewId={2}&amp;Filter=1"/>

    Просто нужно подставить туда:

    1. Id списка,
    2. Внутреннее имя колонки,
    3. ID вьюхи

    Если не знаете что туда написать - просто в браузере в представлении списка отфильтруйте список и посмотрите на URL после postback'a.

    Такой способ в разы быстрее чем SPQuery или Linq.


    LinkedIn Profile

    • Изменено HeToC 1 июня 2012 г. 10:49
    • Предложено в качестве ответа HeToC 2 июня 2012 г. 8:59
    • Помечено в качестве ответа Roman Zhukov 29 июня 2012 г. 12:04
    1 июня 2012 г. 10:48
  • С помощью HttpWebRequest - это интересно. Только в моем случае есть сложность: элементы списка лежат в папках, а выбор надо сделать из нескольких папок. В SPQuery я указывал ViewAttributes = "Scope='RecursiveAll'", а как быть с HttpWebRequest? Возможно такое проделать?

    И еще вопрос про оптимизацию кода. Как можно узнать сколько времени тратится на выполнение той или иной функции? Просто есть желание определить самые длительные куски кода, для его оптимизации.

    1 июня 2012 г. 11:28
  • По поводу оптимизации кода посмотрите вот вот эти ресурсы:

    Но хороший профайлер стоит хороших денег.


    Dmitry

    Lightning Tools LogoLightning Tools Check out our SharePoint tools and web parts | Lightning Tools Blog


    1 июня 2012 г. 11:34
    Отвечающий
  • С помощью HttpWebRequest - это интересно. Только в моем случае есть сложность: элементы списка лежат в папках, а выбор надо сделать из нескольких папок. В SPQuery я указывал ViewAttributes = "Scope='RecursiveAll'", а как быть с HttpWebRequest? Возможно такое проделать?

    Просто укажите ID вьюхи в которой в которой стоит опция показывать все элементы из подпапок и все

    LinkedIn Profile

    1 июня 2012 г. 13:30
  • Можно попробовать серией запросов:

    Взять первый элемент списка, из него выбрать значение. По этому значению сделать CAML на неравенство, выполнить запрос и снова выбрать первый элемент. Продолжать, пока запрос не вернёт пустой набор. Для получения текста запроса  можно использовать Camlex.NET.

    Запросы можно пооптимизировать - включать не все поля и т.д.

    Если повезёт, то можно и ускорение получить.

    А с суммой фокус не пройдёт, надо все перебирать. Если могут попадаться нули, то можно их отсеять, конечно.

    1 июня 2012 г. 16:08
    Отвечающий
  • HeToC, прикольный способ. Любопытно, почему быстрее - там все уходит вроде как не в стандарный caml запрос, в web.Request.RenderViewAsHtml(web.Url, this.InternalName, bstrViewID, bstrViewXml, null, pDataCallback, out pbSharedList, out pbThrottled) и это любопытно. Так же, клева что в filter.aspx есть DelegateControl: <SharePoint:DelegateControl runat="server" ControlId="ColumnFilterCAMLGenerator" /> Т.е. по идее, есть точка кастомизации этого поведения (что есть офигенно), такого в 2007 не было.

    Кстати, Виталий Жуков  напотистил пост об этом, там все мега-быстро, но мега-опасно :)

    Интересно, можно ли прикрутить это к SharePoint:DelegateControl с ColumnFilterCAMLGenerator?

    Получение уникальных значений поля списка

    • Изменено avishnyakov 4 июня 2012 г. 0:53
  • HeToC, прикольный способ. Любопытно, почему быстрее - там все уходит вроде как не в стандарный caml запрос, в web.Request.RenderViewAsHtml(web.Url, this.InternalName, bstrViewID, bstrViewXml, null, pDataCallback, out pbSharedList, out pbThrottled) и это любопытно. Так же, клева что в filter.aspx есть DelegateControl: <SharePoint:DelegateControl runat="server" ControlId="ColumnFilterCAMLGenerator" /> Т.е. по идее, есть точка кастомизации этого поведения (что есть офигенно), такого в 2007 не было.

    Кстати, Виталий Жуков  напотистил пост об этом, там все мега-быстро, но мега-опасно :)

    Интересно, можно ли прикрутить это к SharePoint:DelegateControl с ColumnFilterCAMLGenerator?

    Получение уникальных значений поля списка

    Решение очень интересное. Но у меня не вышло :(. Мне нужно получить уникальные значения для поля типа Lookup. А они в SQL почему-то не отображаются, просто NULL стоит. Через SQL можно было бы решить проблемму и сумированием сразу.
  • У вашего Lookup поля стоит наверное AllowMultipleValues, верно ?

    Тогда выбранные значения хранятся в таблице dbo.AllUserDataJunctions или dbo.UserDataJunctions.

    Смотрите мой ответ в соседней теме.

    ===============================================
    SELECT
        d.nvarchar3 AS vn
        , u.UserName AS un
        , j.tp_ID AS cid
    FROM UserData d --build in SQL data view that filters deleted items
        LEFT OUTER JOIN UserDataJunctions j ON d.tp_LeafName = j.tp_LeafName -- <-- this is the id for the multiple records that you picked
            AND d.tp_DirName = j.tp_DirName -- <-- this and the leafname are needed to make the match and pull the multiple values
        INNER JOIN vCID c ON j.tp_ID = c.cid --my custom view for id listing - not my real view names
        INNER JOIN vGU u ON d.nvarchar3 = u.vn --my custom view to pull user data - not my real view names :)
    WHERE
        d.tp_ListID = 'yourlonglistidhere'


    LinkedIn Profile

    • Изменено HeToC 5 июня 2012 г. 9:39
    • Помечено в качестве ответа Roman Zhukov 29 июня 2012 г. 12:05