Custom Sort Order in CAML Query - sharepoint-2010

How would one go about telling a CAML query to sort the results in a thoroughly custom order?
.
For instance, for a given field:
-- when equal to 'Chestnut' at the top,
-- then equal to 'Zebra' next,
-- then equaling 'House'?
Finally, within those groupings, sort on a second condition (such as 'Name'), normally ascending.
So this
ID Owns Name
————————————————————
1 Zebra Sue
2 House Jim
3 Chestnut Sid
4 House Ken
5 Zebra Bob
6 Chestnut Lou
becomes
ID Owns Name
————————————————————
6 Chestnut Lou
3 Chestnut Sid
5 Zebra Bob
1 Zebra Sue
2 House Jim
4 House Ken
In SQL, this can be done with Case/When. But in CAML? Not so much!

CAML does not have such a sort operator by my knowledge. The workaround might be that you add a calculated column to the list with a number datatype and formula
=IF(Owns="Chestnut",0,IF(Owns="Zebra",1,IF(Owns="House",3,999))).
Now it is possible to order on the calculated column, which translates the custom sort order to numbers. Another solution is that you create a second list with the items to own, and a second column which contains their sort order. You can link these two lists and order by the item list sort order. The benefit is that a change in the sort order is as easy as editing the respective listitems.

Related

T-SQL: How can I order individuals with multiple rows by minimum Rank but keep their rows grouped together?

I'm creating a committee roster report. I have a few hundred rows of data in which I have Name and Position, and each Position has a set Rank, where the lower it is, the higher the Position’s standing in the committee.
I need to sort the VIPs to the top by their most important (lowest) Rank position first and if they have any other positions in the committee, I need those to sort right after that in the list in ascending Rank order, followed by the next best ranking position VIP and their other Positions in ascending Rank order.
Then--after around Rank 100 or so--the list of Positions that are considered VIP ends, so I just want everyone to sort by Name then Rank from then on.
Here's a model of the kind of data I'm trying to sort with it organized in the way I'm hoping for:
RANK
POSITION
NAME
ID
1
Chair
Jane J.
10009
3
Treasurer
Jane J.
10009
9
Editor
Jane J.
10009
2
Vice Chair
Kevin K.
10002
5
Director
Kevin K.
10002
3
President
Laura L.
10003
4
Vice President
Manuel M.
10005
10
Asst. Editor
Manuel M.
10005
100
Member
Anna A.
10010
100
Member
Ben B.
10014
50
Coordinator
Carry C.
10020
100
Member
Carry C.
10020
60
Asst. Coord.
Dennis D.
10008
61
Mbr. Coord.
Dennis D.
10008
Below is a simplified model of the SELECT statement I'm currently working with, which does not accomplish what I'm looking for. I've tried a lot of custom columns in my attempt to make the custom sorting I'm looking for possible, but none have helped.
SELECT
RANK
, POSITION_CODE
, LAST_FIRST
FROM Table
ORDER BY RANK, LAST_FIRST
SELECT
MIN(RANK) OVER (PARTITION BY ID) AS MinRank
, RANK
, POSITION_CODE
, LAST_FIRST
, ID
FROM Table
ORDER BY MinRank, RANK, LAST_FIRST
Edit: Using my new MinRank calculation, I can now first ORDER BY a committee member's Position (POSITION_CODE) with the lowest number RANK (lower numbers for a Position being of greater standing in my committee). This puts the top-ranking Position committee member at the top the top of the list and ascends through everyone else's MinRank, causing the list to sort blocks of names with the same minimum RANK positions together. Then I can ORDER BY RANK ascending, which will sort those blocks in themselves with lesser standing RANK positions. Lastly, I can ORDER BY their names (LAST_FIRST) so that each block of RANK-sorted MinRanks is in alphabetical order by last and first name. For a bonus distinction if needed, I can also ORDER BY ID at the end, to differentiate between those with the same first and last name.
The OVER (PARTITION BY ID) of my MIN(RANK) aggregate is just a shortcut so I don't have to put all my properties into a GROUP BY.

Updating a database column based on its similarity to another database column

I have a database table (Customers) with the following columns:
ID
FIRST_NAME
MIDDLE_INIT
LAST_NAME
FULL_NAME
I also have a database table (ENG) with the following columns:
ID
ENG_NAME
I want to replace all of the ENG.ENG_NAME entries with a FULL_NAME entry from the CUSTOMERS table
Here is the problem.
The ENG_NAME was hand-jammed through a web form and, so, has no consistency. For instance, one row might contain "Robin Hood". Another "Hood, Robin L". An another "Robin L Hood".
I want to search the entries in the CUSTOMERS table, find a close match, then replace the ENG.ENG_NAME with the CUSTOMERS.FULL_NAME.
Example:
ENG table CUSTOMERS table
ID ENG_NAME ID FULL_NAME FIRST_NAME MIDDLE_INIT LAST_NAME
================ ==================================================================
1 Hood,Robin 1 Robin L Hood Robin L Hood
2 Rob Hood 2 Maid M Marion Maid M Marion
3 Marion M 3 Friar F Tuck Friar F Tuck
4 Rob Garza 4 Robert A Garza Robert A Garza
Based on the data above, I would want ENG_NAME columns to be replaced like this:
ENG table
ID ENG_NAME
====================
1 Robin L Hood
2 Robin L Hood
3 Maid M Marion
4 Robert A Garza
Any thoughts on how to do this?
Thanks
This is not going to be a simple task, I would start at finding a good C# (or any .NET) algorithm that detects similar strings portions.
Then look at Compiling C# Code into SQL Stored Procedures and Invoke that code using SQL Server. This CLR Code can then write the results to a table for you to analyze and do whatever you want with it.
For More: CLR SQL Server User-Defined Function
I would do it in .NET using Levenshtein distance.
Start at 1 and you are going to have some ties and you need to decide
Then move to 2,3,4...
You could do in a CLR but how are you going to deal with ties? And you are going to have ties. How are you going to decide when it is not a match at all?
And I would put it in new column so you have a history of original data
Or a FK reference to customers table

MS Access Small Equivalent

I have this working in Excel however it really needs moved into Access as that's where the rest of the database resides.
Its simply one table that contains Unique_ID, Seller and Fruit...
1 Chris Orange
2 Chris Apple
3 Chris Apple
4 Sarah Kiwi
5 Chris Pear
6 Sarah Orange
The end results should be displayed by Seller and then a list of each fruit sold (in the following example Robert has not sold any fruit, I do have a list of all sellers name however this could be ignored in this example as that I believe that will be easy to integrate.) They will only sell a maximum of 20 fruit.
Seller 1st 2nd 3rd 4th
Chris Orange Apple Apple Pear
Sarah Kiwi Orange
Robert
At the moment Excel uses Index, Match and Small to return results. Small is simply used on the Unique_ID to find the 1st, 2nd, 3rd, ect...smallest entries and is matched to each sellers name to build the above results.
As Access doesn't have a Small function I am at a loss! In reality there are over 100,000 records (minimum) with over 4000 sellers....they are also not fruit :)
TRANSFORM First(Sales.Fruit) AS FirstOfFruit
SELECT Sales.Seller
FROM Sales
GROUP BY Sales.Seller
PIVOT DCount([id],"sales","seller='" & [seller] & "' and id<=" & [id]);
Where the table name is "Sales" and the columns are "ID", "Seller" and "Fruit"
To understand DCount better, use it is a SELECT query instead of a crosstab:
SELECT Sales.ID, Sales.Seller, Sales.Fruit, DCount([id],"sales","seller='" & [seller] & "' and id<=" & [id]) AS N
FROM Sales;
On each row, the last column is the DCount result. The syntax is DCount (field, source, expression) so what it does is count the IDs (field) in the Sales table (source) that match the expression - in other words, has the same seller as that row's record and an ID <= the current row's ID. So for Chris's sales, it numbers them 1 through 4, even though Sarah had a sale in the middle.
From this result, it's easy to take a Crosstab query that makes a table with seller in the row and N in the column - putting the sales in order for each seller the way you wanted to see them. The "First" function finds the first fruit for the combination of seller and N for each row and column of the result. You could just as easily use "Max" or "Min" here - any text function. Of course, there is only one record matching the seller row and the N column, but Crosstab queries require a function to evaluate and cannot use "Group by" for the field selected as a Value.
My 1st answer combines these steps - the select and the crosstab queries - in one query.
Hope this helps.

Eliminate duplicate records/rows?

I'm trying to list result from a multi-table query with on row, 2 columns. I have the correct data that I need, I merely need to trim it down to 1 line of results. In other words, eliminate duplicate entries in the result. I'm using a value not shown here, school_id. Should I go with that as a distinct value? Can I do that without displaying the school_id?
SQL> select DISTINCT(school_name),Team_Name
2 from school, team
3 where team.team_name like '%B%'
4 AND school.school_id = team.school_id;
SCHOOL_NAME TEAM_NAME
-------------------------------------------------- ----------
Lawrence Central High School Bears
Lawrence Central High School BEars
Lawrence Central High School BEARS
The problem, as I'm sure you know, is the fact that "Bears" is in 3 different cases here. The simple fix is to do the upper or lower of "Team_Name" so it will only have 1 return record.
UPPER(Team_Name)

Rows to mimic Columns

I want to structure a table to mimic column level filters as row level filter just to avoid adding new columns.
Let's say i have following table to store cars' details
-------------------------------------
Type Color Year
-------------------------------------
Mini Silver 2010
Standard Silver 2011
Fullsize White 2011
Luxury Black 2010
Sports Red 2011
Convertible Red 2009
If i want to store Make of these cars as well and for this i have to add an additional column and another column if i have automobiles other than cars.
So the question is how can i structure this table to avoid adding new columns? The structure should require only to add rows to define properties of my records.
[Hint] The structure may have multiple tables, one to store rows/records and other to store columns/properties and then some kind of mapping between them OR entirely new structure.
EDIT
Some of the properties of my data are fixed and some are dynamic. Fixed properties can be mapped to the given sample Car model as Availability, Condition and the dynamic could be anything which a person may ask about an automobile. Now i don't need all columns to be mapped as rows but few and these are dynamic and i don't even know all of them. My apologies that i didn't mention this earlier.
You could use the entity-attribute-value design (EAV).
entity attribute value
1 Type Mini
1 Color Silver
1 Year 2010
1 Make Foobar
2 Type Standard
2 Color Silver
etc...
You may also wish to store the attribute names in a separate table.
However you should consider carefully if you really need this, as there are a few disadvantages. The value column must have a type that can store all the different types of values (e.g. string). It is much more cumbersome to write queries as you will need many joins, and these queries will run more slowly as compared to a traditional database design.
To give you a head start: Think about redesigning to allow multi-colored vehicles like motorbikes:
vehicle
Id Year vehicle_type vehicle_make
-------------------------------------------
1 2010 1 1
2 2011 2 2
color
Id Name
-----------
1 Black
2 White
3 Red
4 Blue
vehicle_color
vehicle_id color_id
-----------------------
1 3
2 1
2 2
vehicle_type
Id Name
-----------
1 Car
2 Motorbike
vehicle_make
Id Name
-----------
1 Porsche
2 BMW
Bonus
Since I'm quite familiar with the car domain, I'll throw in an extension for your vehicle colors: There are tons of color names ("Magentafuzzyorangesunset") invented by manufacturers and you'll want to map them to "real" base color names ("Red, "Blue", "Green", etc.) to enable searching for both.
Your color table then could look like that
Id Name base_color
-----------------------------
1 Midnight 1
2 Snow 2
and you'll add a base_color table
Id Name
-----------
1 Black
2 White