I have attached one sample.This is like query method.But i am using this query in stored procedure .Query is very fast.But in procedure very slow.What is the reason.
DECLARE #lsId VARCHAR(20);
DECLARE #lsDate VARCHAR(20);
SET #lsId = '802306';
SET #lsDate = '2017-10-02';
SELECT fld_region [REGION],
ISNULL([CINEMA], 0) [CINEMA],
ISNULL([ECONOMY], 0) [ECONOMY],
ISNULL([HD PRIME], 0) [HD PRIME],
ISNULL([HD SUPREME], 0) [HD SUPREME],
ISNULL([HD ULTRA], 0) [HD ULTRA],
ISNULL([INDI], 0) [INDI],
ISNULL([KUSHI], 0) [KUSHI],
ISNULL([MEGA], 0) [MEGA],
ISNULL([ROI VALUE], 0) [ROI VALUE],
ISNULL([ROI VALUE PLUS], 0) [ROI VALUE PLUS],
ISNULL([SOUTH VALUE], 0) [SOUTH VALUE],
ISNULL([SUPER VALUE], 0) [SUPER VALUE],
ISNULL([WORLD], 0) [WORLD]
FROM
(
SELECT b.fld_region,
a.fld_pack_name,
a.fld_count
FROM TBL_ACTIVE_CUSTOMER_DT_PLAN_WISE a
JOIN VHierarchyDT b ON b.FLD_DTCODE = a.FLD_DTCODE
AND b.SH_ID = #lsId
AND a.fld_act_date = #lsDate
) x PIVOT(SUM(fld_count) FOR fld_pack_name IN([CINEMA],
[ECONOMY],
[HD PRIME],
[HD SUPREME],
[HD ULTRA],
[INDI],
[KUSHI],
[MEGA],
[ROI VALUE],
[ROI VALUE PLUS],
[SOUTH VALUE],
[SUPER VALUE],
[WORLD])) p;
Maybe try setting the variable datatypes
DECLARE #lsId INT; --If this is the correct data type
DECLARE #lsDate DATE; --If this is the correct data type
SET #lsId = 802306;
SET #lsDate = '2017-10-02';
SELECT fld_region [REGION],
ISNULL([CINEMA], 0) [CINEMA],
ISNULL([ECONOMY], 0) [ECONOMY],
ISNULL([HD PRIME], 0) [HD PRIME],
ISNULL([HD SUPREME], 0) [HD SUPREME],
ISNULL([HD ULTRA], 0) [HD ULTRA],
ISNULL([INDI], 0) [INDI],
ISNULL([KUSHI], 0) [KUSHI],
ISNULL([MEGA], 0) [MEGA],
ISNULL([ROI VALUE], 0) [ROI VALUE],
ISNULL([ROI VALUE PLUS], 0) [ROI VALUE PLUS],
ISNULL([SOUTH VALUE], 0) [SOUTH VALUE],
ISNULL([SUPER VALUE], 0) [SUPER VALUE],
ISNULL([WORLD], 0) [WORLD]
FROM
(
SELECT b.fld_region,
a.fld_pack_name,
a.fld_count
FROM TBL_ACTIVE_CUSTOMER_DT_PLAN_WISE a
JOIN VHierarchyDT b ON b.FLD_DTCODE = a.FLD_DTCODE
AND b.SH_ID = #lsId
AND a.fld_act_date = #lsDate
) x PIVOT(SUM(fld_count) FOR fld_pack_name IN([CINEMA],
[ECONOMY],
[HD PRIME],
[HD SUPREME],
[HD ULTRA],
[INDI],
[KUSHI],
[MEGA],
[ROI VALUE],
[ROI VALUE PLUS],
[SOUTH VALUE],
[SUPER VALUE],
[WORLD])) p;
OR Pulling initial data into a temporary table
DECLARE #lsId INT; --If this is the correct data type
DECLARE #lsDate DATE; --If this is the correct data type
SET #lsId = 802306;
SET #lsDate = '2017-10-02';
IF OBJECT_ID('tempdb..##PivotData') IS NOT NULL
DROP TABLE ##PivotData
SELECT b.fld_region,
a.fld_pack_name,
a.fld_count
INTO ##PivotData --I would normally create and not select into.
FROM TBL_ACTIVE_CUSTOMER_DT_PLAN_WISE a
JOIN VHierarchyDT b ON b.FLD_DTCODE = a.FLD_DTCODE
AND b.SH_ID = #lsId
AND a.fld_act_date = #lsDate
SELECT fld_region [REGION],
ISNULL([CINEMA], 0) [CINEMA],
ISNULL([ECONOMY], 0) [ECONOMY],
ISNULL([HD PRIME], 0) [HD PRIME],
ISNULL([HD SUPREME], 0) [HD SUPREME],
ISNULL([HD ULTRA], 0) [HD ULTRA],
ISNULL([INDI], 0) [INDI],
ISNULL([KUSHI], 0) [KUSHI],
ISNULL([MEGA], 0) [MEGA],
ISNULL([ROI VALUE], 0) [ROI VALUE],
ISNULL([ROI VALUE PLUS], 0) [ROI VALUE PLUS],
ISNULL([SOUTH VALUE], 0) [SOUTH VALUE],
ISNULL([SUPER VALUE], 0) [SUPER VALUE],
ISNULL([WORLD], 0) [WORLD]
FROM ##PivotData x
PIVOT(SUM(fld_count) FOR fld_pack_name IN([CINEMA],
[ECONOMY],
[HD PRIME],
[HD SUPREME],
[HD ULTRA],
[INDI],
[KUSHI],
[MEGA],
[ROI VALUE],
[ROI VALUE PLUS],
[SOUTH VALUE],
[SUPER VALUE],
[WORLD])) p;
Related
I am new to Snowflake SQL and trying to migrate a code from Oracle SQL to Snowflake SQL.
I am using a subquery in Oracle which is not supported in Snowflake and it gives the following err-r
SQL compilation error: Unsupported subquery type cannot be evaluated.
Original SQL Query -
select p."EMPLOYEE#" as Employee_ID,
(select o."POSITION_NO" from ah_occupancy o where o."EMPLOYEE_NO" = p."EMPLOYEE#" and o."JOB_NO" = p."JOB#" and p."WORKDATE" between o."PORTION_START" and o."PORTION_END") as Position_ID,
j."COMPANY_CODE",
date(p."WORKDATE") as Work_Date,
p."UNIT" as Calculated_Quantity,
p."PAYCODE"
from
"ODS"."HRIS"."PEPAYTRAN" p, job j
where p."EMPLOYEE#" =j."EMPLOYEE#"
and p."JOB#" = j."JOB#"
and date( p."WORKDATE") between '2021-02-04' and '2021-02-10'-->='11-FEB-2021'
and p."ORIGIN" not in ('RC101','FC801','WK8276')
and p."PAYCODE" not in ('GPPL', 'CLAMS')
and p."PAYCODE" not like 'JK%'
and p."TP" >= '01-JAN-2021'
and nvl(p."BATCH#",' ') not in ('MUHTSL','MUHTS','ICWTS','RDOAC','NU011','1')) ;
I reframed the query and it compiles and gives the same number of records, can anyone review the code and comment if its the same or if its in correct, kindly comment on same.
select p."EMPLOYEE#" as Employee_ID,
o.position_no as Position_ID,
j."COMPANY_CODE",
date(p."WORKDATE") as Work_Date,
p."UNIT" as Calculated_Quantity,
p."PAYCODE"
from
"ODS"."HRIS"."PEPAYTRAN" p, "ODS"."HRIS"."JOB" j, "ODS"."HRIS"."AH_OCCUPANCY" o
where p."EMPLOYEE#" =j."EMPLOYEE#"
and p."JOB#" = j."JOB#"
and date( p."WORKDATE") between '2021-02-04' and '2021-02-10'-->='11-FEB-2021'
and p."ORIGIN" not in ('RC101','FC801','WK8276')
and p."PAYCODE" not in ('GPPL', 'CLAMS')
and p."PAYCODE" not like 'JK%'
and p."TP" >= '01-JAN-2021'
and nvl(p."BATCH#",' ') not in ('MUHTSL','MUHTS','ICWTS','RDOAC','NU011','1')
and o."EMPLOYEE_NO" = p."EMPLOYEE#" and o."JOB_NO" = p."JOB#" and p."WORKDATE" between o."PORTION_START" and o."PORTION_END"
Both queries are equivalent. You can check that both return the same information by running the following query:
--original query
select
p."EMPLOYEE#" as Employee_ID,
(select
o."POSITION_NO"
from
ah_occupancy o
where
o."EMPLOYEE_NO" = p."EMPLOYEE#"
and o."JOB_NO" = p."JOB#"
and p."WORKDATE" between o."PORTION_START" and o."PORTION_END"
) as Position_ID,
j."COMPANY_CODE",
date(p."WORKDATE") as Work_Date,
p."UNIT" as Calculated_Quantity,
p."PAYCODE"
from
"ODS"."HRIS"."PEPAYTRAN" p,
job j
where
p."EMPLOYEE#" =j."EMPLOYEE#"
and p."JOB#" = j."JOB#"
and date( p."WORKDATE") between '2021-02-04' and '2021-02-10'-->='11-FEB-2021'
and p."ORIGIN" not in ('RC101','FC801','WK8276')
and p."PAYCODE" not in ('GPPL', 'CLAMS')
and p."PAYCODE" not like 'JK%'
and p."TP" >= '01-JAN-2021'
and nvl(p."BATCH#",' ') not in ('MUHTSL','MUHTS','ICWTS','RDOAC','NU011','1')) ;
minus
--new query
select
p."EMPLOYEE#" as Employee_ID,
o.position_no as Position_ID,
j."COMPANY_CODE",
date(p."WORKDATE") as Work_Date,
p."UNIT" as Calculated_Quantity,
p."PAYCODE"
from
"ODS"."HRIS"."PEPAYTRAN" p,
"ODS"."HRIS"."JOB" j,
"ODS"."HRIS"."AH_OCCUPANCY" o
where
p."EMPLOYEE#" =j."EMPLOYEE#"
and p."JOB#" = j."JOB#"
and date( p."WORKDATE") between '2021-02-04' and '2021-02-10'-->='11-FEB-2021'
and p."ORIGIN" not in ('RC101','FC801','WK8276')
and p."PAYCODE" not in ('GPPL', 'CLAMS')
and p."PAYCODE" not like 'JK%'
and p."TP" >= '01-JAN-2021'
and nvl(p."BATCH#",' ') not in ('MUHTSL','MUHTS','ICWTS','RDOAC','NU011','1')
and o."EMPLOYEE_NO" = p."EMPLOYEE#"
and o."JOB_NO" = p."JOB#"
and p."WORKDATE" between o."PORTION_START" and o."PORTION_END"
You can also try the following query which is also equivalent:
select
p."EMPLOYEE#" as Employee_ID,
o.position_no as Position_ID,
j."COMPANY_CODE",
date(p."WORKDATE") as Work_Date,
p."UNIT" as Calculated_Quantity,
p."PAYCODE"
from
"ODS"."HRIS"."PEPAYTRAN" p
inner join "ODS"."HRIS"."JOB" j
on (p."EMPLOYEE#" =j."EMPLOYEE#"
and p."JOB#" = j."JOB#")
inner join "ODS"."HRIS"."AH_OCCUPANCY" o
on (o."EMPLOYEE_NO" = p."EMPLOYEE#"
and o."JOB_NO" = p."JOB#"
and p."WORKDATE" between o."PORTION_START" and o."PORTION_END" )
where
date( p."WORKDATE") between '2021-02-04' and '2021-02-10'-->='11-FEB-2021'
and p."ORIGIN" not in ('RC101','FC801','WK8276')
and p."PAYCODE" not in ('GPPL', 'CLAMS')
and p."PAYCODE" not like 'JK%'
and p."TP" >= '01-JAN-2021'
and nvl(p."BATCH#",' ') not in ('MUHTSL','MUHTS','ICWTS','RDOAC','NU011','1')
I am trying to get the blood type of each generation (parents and grandparents) by randomly assigning the child alleles. I ended up hardcoding it. Is there any way to revise the code by using recursion so I won't be hardcoding? Any suggestions would be greatly appreciated!
> // Create a new individual with `generations` person
> *create_family(int generations) {
> // create a new person and use it potentially to get the ancestors
> person *p = malloc(sizeof(person));
> p -> alleles[0] = random_allele();
> p -> alleles[1] = random_allele();
> // Recursively create blood type histories for parents
> person *parent1 = malloc(sizeof(person));
> person *parent2 = malloc(sizeof(person));
> person *grandparent1 = malloc(sizeof(person));
> person *grandparent2 = malloc(sizeof(person));
> person *grandparent3 = malloc(sizeof(person));
> person *grandparent4 = malloc(sizeof(person));
>
> // update the new person's parents
> if ((parent1 == NULL) || (parent2 == NULL) || (grandparent1 == NULL) || (grandparent2 == NULL) || (grandparent3 == NULL) ||
> (grandparent4 == NULL))
> {
> return false;
> }
> // Generation with parent data
> if (generations > 1)
> {
> if (p == NULL)
> {
> return false;
> }
> if (p != NULL)
> {
> //set parent[0] equals the recursive call
> p -> parents[0] = parent1;
> p -> parents[1] = parent2;
>
> parent1 -> parents[0] = grandparent1;
> parent1 -> parents[1] = grandparent2;
> parent2 -> parents[0] = grandparent3;
> parent2 -> parents[1] = grandparent4;
>
> // Randomly assign child alleles based on parents
> parent1 -> alleles[0] = p -> alleles[0];
> parent1 -> alleles[1] = random_allele();
> parent2 -> alleles[0] = p -> alleles[1];
> parent2 -> alleles[1] = random_allele();
>
> grandparent1 -> alleles[0] = parent1 -> alleles[0];
> grandparent1 -> alleles[1] = random_allele();
> grandparent2 -> alleles[0] = parent1 -> alleles[1];
> grandparent2 -> alleles[1] = random_allele();
> grandparent3 -> alleles[0] = parent2 -> alleles[0];
> grandparent3 -> alleles[1] = random_allele();
> grandparent4 -> alleles[0] = parent2 -> alleles[1];
> grandparent4 -> alleles[1] = random_allele();
> }
> }
> }
This is a good case for recursion. Updated to pass the child's allele to the parent
// Call this function
person * create_family(int generations)
{
return create_family_recursive(generations, random_allele());
}
// This function only gets called by the other
person * create_family_recursive(int generations, allele *parent_allele)
{
if (generations == 0) return NULL; // End recursion
// Create a person
person * child = malloc(sizeof(person));
child->alleles[0] = parent_allele;
child->alleles[1] = random_allele();
// Create 2 parents (and all generations prior)
child->parents[0] = create_family(generations - 1, child->alleles[0]);
child->parents[1] = create_family(generations - 1, child->alleles[1]);
return child;
}
There are no compiler errors and this is where I get the key presses:
while (handle_keys()) {
Sleep(20);
Bkey_GetKeyWait(key1, key2, KEYWAIT_HALTOFF_TIMEROFF, 0, 1, & unused);
fill_old_squares();
ball_update();
angle += 1;
ball_draw(WHITE);
draw_stars();
Bdisp_PutDisp_DD();
}
and this is where I handle the key presses:
int handle_keys() {
if (key1 == 3 && key2 == 2) { //EXE key
ball_jump();
} else if (key1 == 4 && key2 == 8) { //EXIT key
return FALSE;
} else if (key1 == 4 && key2 == 9) { //MENU key
return FALSE;
}
key1 = key2 = 0;
return TRUE;
}
It says: TARGET=00000000 PC=00000001
The BKey_GetKeyWait function takes int references as the first 2 arguments.
If key1 and key2 are normal ints than you will need to change it from:
Bkey_GetKeyWait(key1, key2, KEYWAIT_HALTOFF_TIMEROFF, 0, 1, & unused);
to:
Bkey_GetKeyWait(&key1, &key2, KEYWAIT_HALTOFF_TIMEROFF, 0, 1, & unused);
I am using Obtics library for my live-linq queries.
But I can't get pass this weird exception which makes no sense at all.
Here is my query:
var query = ExpressionObserver.Execute(() =>
from o in _orders.DefaultIfEmpty(new OrderStatusViewModel())
where o.State != OrderStateEnum.Canceled
group o by o.Isin
into g
let name = _referenceData.GetInstrumentName(g.Key)
orderby name ascending
select new ComplexRowViewModel(_referenceData)
{
UnderlyingOrder = g.First(),
PrimaryExchange = (from q in _quotes.DefaultIfEmpty(new QuoteTickViewModel()).Where(w => w.Exchange == _referenceData.GetPrimaryExchangeId(g.Key) && w.Isin == g.Key && w.Provider == ProviderEnum.Bloomberg)
select new SimpleRowViewModel()
{
UnderlyingQuote = q
}).First(),
Groupped = (from y in _orders.DefaultIfEmpty(new OrderStatusViewModel())
join x in _quotes.DefaultIfEmpty(new QuoteTickViewModel()) on new { y.Isin, y.Exchange }
equals new { x.Isin, x.Exchange }
where
y.Isin == g.Key &&
y.State != OrderStateEnum.Canceled &&
x.Provider == ProviderEnum.Tradebase &&
x.Exchange !=
_referenceData.GetPrimaryExchangeId(g.Key)
group x by new { x.Exchange }
into p
select new SimpleRowViewModel()
{
UnderlyingQuote = p.First()
}
),
Uncompressed = (from o in _orders.DefaultIfEmpty(new OrderStatusViewModel())
where o.State != OrderStateEnum.Canceled && o.Isin == g.Key
select new UncompressedRowViewModel() { UnderlyingOrder = o }),
Compressed = (from o in _orders.DefaultIfEmpty(new OrderStatusViewModel())
where o.State != OrderStateEnum.Canceled && o.Isin == g.Key
group o by new { o.LimitPrice, o.OrderSide } into x
select new CompressedRowViewModel()
{
Ask = x.Key.OrderSide == OrderSideEnum.Sell ? (decimal?)x.Key.LimitPrice : (decimal?)null,
AskSize = x.Key.OrderSide == OrderSideEnum.Sell ? x.Select(s => s.Quantity).Aggregate((c, n) => c + n) : 0,
Bid = x.Key.OrderSide == OrderSideEnum.Buy ? (decimal?)x.Key.LimitPrice : (decimal?)null,
BidSize = x.Key.OrderSide == OrderSideEnum.Buy ? x.Select(s => s.Quantity).Aggregate((c, n) => c + n) : 0,
Exchange = string.Join(", ", x.Select(s => s.Exchange)),
Isin = x.First().Isin.ToString(),
OrderBuyCount = x.Key.OrderSide == OrderSideEnum.Buy ? x.Count() : 0,
OrderSellCount = x.Key.OrderSide == OrderSideEnum.Sell ? x.Count() : 0,
RowSide = x.Key.OrderSide == OrderSideEnum.Sell ? RowSide.Sell : RowSide.Buy
})}
).Cascade();
GridData = query;
I uploaded the class which makes all this possible. http://www.4shared.com/file/ce_V8PPh/MarketData.html
The exception is:
InvalidOperationException, Added item does not appear at given index '0'.
But this makes no sense since the item is already there.
Everything works fine until an OrderStatus gets a "Cancelled" state. I think it is because I filter the cancelled orders on top of the query, but how is this relevant I don't know.
I finally found a solution to my problem. It turns out that Obtics has a problem with on the fly class creation with lambda, such as
from o in orders where o.state == "active" select new OrderModel2 {Underlying = o}
new keyword messes all up. you need handle this class creation manually.
Anyways after 2 days of head smashing I ended up having this much code.
private void CreateQueries()
{
var query = ExpressionObserver.Execute(() => (from o in _orders
where o.State != OrderStateEnum.Canceled
group o by o.Isin
into g
let name = _referenceData.GetInstrumentName(g.Key)
orderby name ascending
select GetComplexRowViewModel(
g.First()
,
(from p in _quotes
where
p.Isin == g.Key &&
p.Exchange == _referenceData.GetPrimaryExchangeId(g.Key) &&
p.Provider == ProviderEnum.Bloomberg
select GetSimpleRowViewModel(p))
,
(from q in _quotes
where
q.Isin == g.Key &&
q.Provider == ProviderEnum.Tradebase &&
g.Select(s => s.Exchange).Contains(q.Exchange)
select GetSimpleRowViewModel(q))
,
(from o in _orders
where o.Isin == g.Key
&& o.State != OrderStateEnum.Canceled
group o by new { o.LimitPrice, o.OrderSide } into x
select GetCompressedRowViewModel
(
x.Key.OrderSide == OrderSideEnum.Sell ? (decimal?)x.Key.LimitPrice : (decimal?)null,
x.Key.OrderSide == OrderSideEnum.Sell ? x.Select(s => s.Quantity).Aggregate((c, n) => c + n) : 0,
x.Key.OrderSide == OrderSideEnum.Buy ? (decimal?)x.Key.LimitPrice : (decimal?)null,
x.Key.OrderSide == OrderSideEnum.Buy ? x.Select(s => s.Quantity).Aggregate((c, n) => c + n) : 0,
string.Join(", ", x.Select(s => s.Exchange)),
x.First().Isin.ToString(),
x.Key.OrderSide == OrderSideEnum.Buy ? x.Count() : 0,
x.Key.OrderSide == OrderSideEnum.Sell ? x.Count() : 0,
x.Key.OrderSide == OrderSideEnum.Sell ? RowSide.Sell : RowSide.Buy
))
,
(from o in _orders
where o.Isin == g.Key
&& o.State != OrderStateEnum.Canceled
select GetUncompressedRowViewModel(o))
))).Cascade();
GridData = query;
}
// Obtics
private ConcurrentDictionary<string, ComplexRowViewModel> _complexRowViewModels = new ConcurrentDictionary<string, ComplexRowViewModel>();
private ComplexRowViewModel GetComplexRowViewModel(OrderStatusViewModel model, IEnumerable<SimpleRowViewModel> primaryExchanges, IEnumerable<SimpleRowViewModel> groupped
, IEnumerable<CompressedRowViewModel> compressed, IEnumerable<UncompressedRowViewModel> uncompressed)
{
if (model == null)
return _complexRowViewModels.GetOrAdd("", s2 => new ComplexRowViewModel());
return _complexRowViewModels.GetOrAdd(model.Isin,
s2 =>
new ComplexRowViewModel(_referenceData) { UnderlyingOrder = model, PrimaryExchange = primaryExchanges.DefaultIfEmpty(new SimpleRowViewModel()).First(), Groupped = groupped, Compressed = compressed, Uncompressed = uncompressed });
}
private ConcurrentDictionary<string, SimpleRowViewModel> _simpleRowViewModels = new ConcurrentDictionary<string, SimpleRowViewModel>();
private SimpleRowViewModel GetSimpleRowViewModel(QuoteTickViewModel model)
{
if (model == null)
return _simpleRowViewModels.GetOrAdd("", s2 => new SimpleRowViewModel());
return _simpleRowViewModels.GetOrAdd(model.Isin + model.Exchange,
s2 =>
new SimpleRowViewModel() { UnderlyingQuote = model });
}
private ConcurrentDictionary<string, UncompressedRowViewModel> _uncompressedRowViewModels = new ConcurrentDictionary<string, UncompressedRowViewModel>();
private UncompressedRowViewModel GetUncompressedRowViewModel(OrderStatusViewModel model)
{
if (model == null)
return _uncompressedRowViewModels.GetOrAdd("", s2 => new UncompressedRowViewModel());
return _uncompressedRowViewModels.GetOrAdd(model.InternalId,
s2 =>
new UncompressedRowViewModel() { UnderlyingOrder = model });
}
private ConcurrentDictionary<string, CompressedRowViewModel> _compressedRowViewModels = new ConcurrentDictionary<string, CompressedRowViewModel>();
private CompressedRowViewModel GetCompressedRowViewModel(decimal? Ask, int AskSize, decimal? Bid, int BidSize, string Exchange, string Isin, int OrderBuyCount, int OrderSellCount, RowSide RowSide)
{
return new CompressedRowViewModel()
{
Ask = Ask,
AskSize = AskSize,
Bid = Bid,
BidSize = BidSize,
Exchange = Exchange,
Isin = Isin,
OrderBuyCount = OrderBuyCount,
OrderSellCount = OrderSellCount,
RowSide = RowSide
};
}
It works but looks ugly, if anyone has a way to make it more beautiful I'll be appreciated.
The problem is not with the 'new' keyword but rather that two instances of type OrderModel2 are not equal even though they are created with equal construction arguments.
This can be solved in three ways:
Override the Equals method of your object.
Apply an ObticsEqualityComparerAttribute to your class with the specific equality comparer for Obtics to use.
Create a factory with a repository that returns the same object instance when called with the same construction arguments.
You seem to have used number 3, though I think your code could be more simple and generic.
I need to implement a function for moving records up and down (sorting) and saving the sortorder with Linq to SQL. I am using SQL Server 2000 but I might be able to upgrade if there is a solution for it with a newer version of SQL Server. I would love to hear any thoughts you might have on how to do it.
Just add an integer column Index to the table and modify this index based on the user input - moving up is just decrementing the index value of the selected record and incrementing the index value of the preceding record.
public void MoveUp(Guid id)
{
Item item = Context.Items.Single(i => i.Id == id);
if (item.Index > 0)
{
Item predecessor = Context.Items.Single(i => i.Index == item.Index - 1);
item.Index -= 1;
predecessor.Index += 1;
Context.SaveChanges();
}
}
Do the opposite for moving down and you are done. If you need this for multiple tables, just create a generic version using an interface.
Thanks Daniel!
From looking at your example I came up with this for sorting products within a category.
public void MoveUp(int categoryId, int productId, int originalIndex, int newIndex)
{
if (newIndex == originalIndex) return;
var product = _context.CategoryProducts.Single(x => x.CategoryId == categoryId && x.ProductId == productId);
product.SortOrder = newIndex;
_context.CategoryProducts
.Where(x =>
x.CategoryId == categoryId &&
x.ProductId != productId &&
x.SortOrder >= newIndex &&
x.SortOrder <= originalIndex)
.Update(x => { x.SortOrder = x.SortOrder + 1; });
_context.SubmitChanges();
}
public void MoveDown(int categoryId, int productId, int originalIndex, int newIndex)
{
if (newIndex == originalIndex) return;
var product = _context.CategoryProducts.Single(x => x.CategoryId == categoryId && x.ProductId == productId);
product.SortOrder = newIndex;
_context.CategoryProducts
.Where(x =>
x.CategoryId == categoryId &&
x.ProductId != productId &&
x.SortOrder >= originalIndex &&
x.SortOrder <= newIndex)
.Update(x => { x.SortOrder = x.SortOrder - 1; });
_context.SubmitChanges();
}
I used the UpdatedExtension from Hooked on LINQ for the actual updating.