last_Value函数的使用(SQL SERVER 2012RC)

本文通过具体实例展示了如何在SQL中使用LAST_VALUE函数来获取指定字段的最后一个值,包括不分组和按ID分组的情况,并简要提及了FIRST_VALUE函数的用法。

时常, 我们想取回最值记录, 比如,最后日期什么的,

看一个例子,

if OBJECT_ID('test','u') is not null
drop table test
go
create table test(
Id int,
Name nvarchar(50),
Date date,
Amount int)
go
insert into test(Id,Name,Date,Amount)
values
(1,'张三','2011-01-22',15),
(1,'张三','2011-01-28',20),
(2,'李四','2011-01-02',5),
(2,'李四','2011-01-18',8),
(2,'李四','2011-02-14',17)
go
select * from test


现在, 我们想要最后日期的记录, 可以使用LAST_VALUE函数,

select Id,Name,Date,Amount,
LAST_VALUE(Id) over(order by Date RANGE BETWEEN UNBOUNDED PRECEDING
                    AND UNBOUNDED FOLLOWING) as LastId,
LAST_VALUE(Name) over(order by Date RANGE BETWEEN UNBOUNDED PRECEDING
                    AND UNBOUNDED FOLLOWING) as LastName,
LAST_VALUE(Amount) over(order by Date RANGE BETWEEN UNBOUNDED PRECEDING
                    AND UNBOUNDED FOLLOWING) as LastAmount
					from test
					order by Id

如果我们想要按照ID分组呢?,非常简单,

select Id,Name,Date,Amount,
LAST_VALUE(Id) over(PARTITION BY ID order by Date RANGE BETWEEN UNBOUNDED PRECEDING
                    AND UNBOUNDED FOLLOWING) as LastId,
LAST_VALUE(Name) over(PARTITION BY ID order by Date RANGE BETWEEN UNBOUNDED PRECEDING
                    AND UNBOUNDED FOLLOWING) as LastName,
LAST_VALUE(Amount) over(PARTITION BY ID order by Date RANGE BETWEEN UNBOUNDED PRECEDING
                    AND UNBOUNDED FOLLOWING) as LastAmount
					from test
					order by Id


FIRST_VALUE使用和LAST_VALUE一样,

/* Copyright (c) 2007-2013 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see <http://www.gnu.org/licenses/ >. */ #ifndef __ZMQ_YPIPE_HPP_INCLUDED__ #define __ZMQ_YPIPE_HPP_INCLUDED__ #include "atomic_ptr.hpp" #include "yqueue.hpp" // Lock-free queue implementation. // Only a single thread can read from the pipe at any specific moment. // Only a single thread can write to the pipe at any specific moment. // T is the type of the object in the queue. // N is granularity of the pipe, i.e. how many items are needed to // perform next memory allocation. template <typename T, int N> class ypipe_t { public: // Initialises the pipe. inline ypipe_t() { // Insert terminator element into the queue. queue.push(); //yqueue_t的尾指针加1,开始back_chunk为空,现在back_chunk指向第一个chunk_t块的第一个位置 // Let all the pointers to point to the terminator. // (unless pipe is dead, in which case c is set to NULL). r = w = f = &queue.back(); //就是让r、w、f、c四个指针都指向这个end迭代器 c.set(&queue.back()); } // The destructor doesn't have to be virtual. It is mad virtual // just to keep ICC and code checking tools from complaining. inline virtual ~ypipe_t() { } // Following function (write) deliberately copies uninitialised data // when used with zmq_msg. Initialising the VSM body for // non-VSM messages won't be good for performance. #ifdef ZMQ_HAVE_OPENVMS #pragma message save #pragma message disable(UNINIT) #endif // Write an item to the pipe. Don't flush it yet. If incomplete is // set to true the item is assumed to be continued by items // subsequently written to the pipe. Incomplete items are neverflushed down the stream. // 写入数据,incomplete参数表示写入是否还没完成,在没完成的时候不会修改flush指针,即这部分数据不会让读线程看到。 inline void write(const T &value_, bool incomplete_) { // Place the value to the queue, add new terminator element. queue.back() = value_; queue.push(); // Move the "flush up to here" poiter. if (!incomplete_) { f = &queue.back(); // 记录要刷新的位置 // printf("1 f:%p, w:%p\n", f, w); } else { // printf("0 f:%p, w:%p\n", f, w); } } #ifdef ZMQ_HAVE_OPENVMS #pragma message restore #endif // Pop an incomplete item from the pipe. Returns true is such // item exists, false otherwise. inline bool unwrite(T *value_) { if (f == &queue.back()) return false; queue.unpush(); *value_ = queue.back(); return true; } // Flush all the completed items into the pipe. Returns false if // the reader thread is sleeping. In that case, caller is obliged to // wake the reader up before using the pipe again. // 刷新所有已经完成的数据到管道,返回false意味着读线程在休眠,在这种情况下调用者需要唤醒读线程。 // 批量刷新的机制, 写入批量后唤醒读线程; // 反悔机制 unwrite inline bool flush() { // If there are no un-flushed items, do nothing. if (w == f) // 不需要刷新,即是还没有新元素加入 return true; // Try to set 'c' to 'f'. // read时如果没有数据可以读取则c的值会被置为NULL if (c.cas(w, f) != w) // 尝试将c设置为f,即是准备更新w的位置 { // Compare-and-swap was unseccessful because 'c' is NULL. // This means that the reader is asleep. Therefore we don't // care about thread-safeness and update c in non-atomic // manner. We'll return false to let the caller know // that reader is sleeping. c.set(f); // 更新为新的f位置 w = f; return false; //线程看到flush返回false之后会发送一个消息给读线程,这需要写业务去做处理 } else // 读端还有数据可读取 { // Reader is alive. Nothing special to do now. Just move // the 'first un-flushed item' pointer to 'f'. w = f; // 更新f的位置 return true; } } // Check whether item is available for reading. // 这里面有两个点,一个是检查是否有数据可读,一个是预取 inline bool check_read() { // Was the value prefetched already? If so, return. if (&queue.front() != r && r) //判断是否在前几次调用read函数时已经预取数据了return true; return true; // There's no prefetched value, so let us prefetch more values. // Prefetching is to simply retrieve the // pointer from c in atomic fashion. If there are no // items to prefetch, set c to NULL (using compare-and-swap). // 两种情况 // 1. 如果c值和queue.front(), 返回c值并将c值置为NULL,此时没有数据可读 // 2. 如果c值和queue.front(), 返回c值,此时可能有数据度的去 r = c.cas(&queue.front(), NULL); //尝试预取数据 // If there are no elements prefetched, exit. // During pipe's lifetime r should never be NULL, however, // it can happen during pipe shutdown when items are being deallocated. if (&queue.front() == r || !r) //判断是否成功预取数据 return false; // There was at least one value prefetched. return true; } // Reads an item from the pipe. Returns false if there is no value. // available. inline bool read(T *value_) { // Try to prefetch a value. if (!check_read()) return false; // There was at least one value prefetched. // Return it to the caller. *value_ = queue.front(); queue.pop(); return true; } // Applies the function fn to the first elemenent in the pipe // and returns the value returned by the fn. // The pipe mustn't be empty or the function crashes. inline bool probe(bool (*fn)(T &)) { bool rc = check_read(); // zmq_assert(rc); return (*fn)(queue.front()); } protected: // Allocation-efficient queue to store pipe items. // Front of the queue points to the first prefetched item, back of // the pipe points to last un-flushed item. Front is used only by // reader thread, while back is used only by writer thread. yqueue_t<T, N> queue; // Points to the first un-flushed item. This variable is used // exclusively by writer thread. T *w; //指向第一个未刷新的元素,只被写线程使用 // Points to the first un-prefetched item. This variable is used // exclusively by reader thread. T *r; //指向第一个还没预提取的元素,只被读线程使用 // Points to the first item to be flushed in the future. T *f; //指向下一轮要被刷新的一批元素中的第一个 // The single point of contention between writer and reader thread. // Points past the last flushed item. If it is NULL, // reader is asleep. This pointer should be always accessed using // atomic operations. atomic_ptr_t<T> c; //读写线程共享的指针,指向每一轮刷新的起点(看代码的时候会详细说)。当c为空时,表示读线程睡眠(只会在读线程中被设置为空) // Disable copying of ypipe object. ypipe_t(const ypipe_t &); const ypipe_t &operator=(const ypipe_t &); }; #endif /* Copyright (c) 2007-2013 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see <http://www.gnu.org/licenses/ >. */ #ifndef __ZMQ_YQUEUE_HPP_INCLUDED__ #define __ZMQ_YQUEUE_HPP_INCLUDED__ #include <stdlib.h> #include <stddef.h> // #include "err.hpp" #include "atomic_ptr.hpp" // yqueue is an efficient queue implementation. The main goal is // to minimise number of allocations/deallocations needed. Thus yqueue // allocates/deallocates elements in batches of N. // // yqueue allows one thread to use push/back function and another one // to use pop/front functions. However, user must ensure that there's no // pop on the empty queue and that both threads don't access the same // element in unsynchronised manner. // // T is the type of the object in the queue. 队列中元素的类型 // N is granularity(粒度) of the queue (how many pushes have to be done till actual memory allocation is required). // 即是yqueue_t一个结点可以装载N个T类型的元素, yqueue_t的一个结点是一个数组 template <typename T, int N> class yqueue_t { public: // 创建队列. inline yqueue_t() { begin_chunk = (chunk_t *)malloc(sizeof(chunk_t)); alloc_assert(begin_chunk); begin_pos = 0; back_chunk = NULL; //back_chunk总是指向队列中最后一个元素所在的chunk,现在还没有元素,所以初始为空 back_pos = 0; end_chunk = begin_chunk; //end_chunk总是指向链表的最后一个chunk end_pos = 0; } // 销毁队列. inline ~yqueue_t() { while (true) { if (begin_chunk == end_chunk) { free(begin_chunk); break; } chunk_t *o = begin_chunk; begin_chunk = begin_chunk->next; free(o); } chunk_t *sc = spare_chunk.xchg(NULL); free(sc); } // Returns reference to the front element of the queue. // If the queue is empty, behaviour is undefined. // 返回队列头部元素的引用,调用者可以通过该引用更新元素,结合pop实现出队列操作。 inline T &front() // 返回的是引用,是个左值,调用者可以通过其修改容器的值 { return begin_chunk->values[begin_pos]; } // Returns reference to the back element of the queue. // If the queue is empty, behaviour is undefined. // 返回队列尾部元素的引用,调用者可以通过该引用更新元素,结合push实现插入操作。 // 如果队列为空,该函数是不允许被调用。 inline T &back() // 返回的是引用,是个左值,调用者可以通过其修改容器的值 { return back_chunk->values[back_pos]; } // Adds an element to the back end of the queue. inline void push() { back_chunk = end_chunk; back_pos = end_pos; // if (++end_pos != N) //end_pos!=N表明这个chunk节点还没有满 return; chunk_t *sc = spare_chunk.xchg(NULL); // 为什么设置为NULL? 因为如果把之前值取出来了则没有spare chunk了,所以设置为NULL if (sc) // 如果有spare chunk则继续复用它 { end_chunk->next = sc; sc->prev = end_chunk; } else // 没有则重新分配 { // static int s_cout = 0; // printf("s_cout:%d\n", ++s_cout); end_chunk->next = (chunk_t *)malloc(sizeof(chunk_t)); // 分配一个chunk alloc_assert(end_chunk->next); end_chunk->next->prev = end_chunk; } end_chunk = end_chunk->next; end_pos = 0; } // Removes element from the back end of the queue. In other words // it rollbacks last push to the queue. Take care: Caller is // responsible for destroying the object being unpushed. // The caller must also guarantee that the queue isn't empty when // unpush is called. It cannot be done automatically as the read // side of the queue can be managed by different, completely // unsynchronised thread. // 必须要保证队列不为空,参考ypipe_t的uwrite inline void unpush() { // First, move 'back' one position backwards. if (back_pos) // 从尾部删除元素 --back_pos; else { back_pos = N - 1; // 回退到前一个chunk back_chunk = back_chunk->prev; } // Now, move 'end' position backwards. Note that obsolete end chunk // is not used as a spare chunk. The analysis shows that doing so // would require free and atomic operation per chunk deallocated // instead of a simple free. if (end_pos) // 意味着当前的chunk还有其他元素占有 --end_pos; else { end_pos = N - 1; // 当前chunk没有元素占用,则需要将整个chunk释放 end_chunk = end_chunk->prev; free(end_chunk->next); end_chunk->next = NULL; } } // Removes an element from the front end of the queue. inline void pop() { if (++begin_pos == N) // 删除满一个chunk才回收chunk { chunk_t *o = begin_chunk; begin_chunk = begin_chunk->next; begin_chunk->prev = NULL; begin_pos = 0; // 'o' has been more recently used than spare_chunk, // so for cache reasons we'll get rid of the spare and // use 'o' as the spare. chunk_t *cs = spare_chunk.xchg(o); //由于局部性原理,总是保存最新的空闲块而释放先前的空闲快 free(cs); } } private: // Individual memory chunk to hold N elements. // 链表结点称之为chunk_t struct chunk_t { T values[N]; //每个chunk_t可以容纳N个T类型的元素,以后就以一个chunk_t为单位申请内存 chunk_t *prev; chunk_t *next; }; // Back position may point to invalid memory if the queue is empty, // while begin & end positions are always valid. Begin position is // accessed exclusively be queue reader (front/pop), while back and // end positions are accessed exclusively by queue writer (back/push). chunk_t *begin_chunk; // 链表头结点 int begin_pos; // 起始点 chunk_t *back_chunk; // 队列中最后一个元素所在的链表结点 int back_pos; // 尾部 chunk_t *end_chunk; // 拿来扩容的,总是指向链表的最后一个结点 int end_pos; // People are likely to produce and consume at similar rates. In // this scenario holding onto the most recently freed chunk saves // us from having to call malloc/free. atomic_ptr_t<chunk_t> spare_chunk; //空闲块(把所有元素都已经出队的块称为空闲块),读写线程的共享变量 // Disable copying of yqueue. yqueue_t(const yqueue_t &); const yqueue_t &operator=(const yqueue_t &); }; #endif #include <atomic> #include <pthread.h> #include <mutex> #include <condition_variable> // 全局计数器 extern int s_queue_item_num; // 每个生产者要插入的元素数 extern int s_producer_thread_num; extern int s_consumer_thread_num; extern int s_count_push; // 全局序号生成器 extern int s_count_pop; // 全局消费计数 /* 原子加:返回加后的值 */ static int lxx_atomic_add(int *ptr, int increment) { int old_value = *ptr; __asm__ volatile("lock; xadd %0, %1 \n\t" : "=r"(old_value), "=m"(*ptr) : "0"(increment), "m"(*ptr) : "cc", "memory"); return *ptr; } #include "ypipe.hpp" // 你自己的 ypipe_t 实现 ypipe_t<int, 10000> yqueue; /* 生产者线程函数(单元素 flush) */ void *yqueue_producer_thread(void *argv) { for (int i = 0; i < s_queue_item_num; ++i) { int unique = lxx_atomic_add(&s_count_push, 1); yqueue.write(unique, false); // 写入元素 yqueue.flush(); // 立即刷新,对消费者可见 } return nullptr; } /* 消费者线程函数 */ void *yqueue_consumer_thread(void *argv) { int last_value = 0; while (true) { int value; if (yqueue.read(&value)) // 非阻塞读取 { last_value = value; lxx_atomic_add(&s_count_pop, 1); } else { usleep(100); // 空队列时小睡 } if (s_count_pop >= s_queue_item_num * s_producer_thread_num) break; // 全部消费完退出 } return nullptr; } int main() { s_queue_item_num = 2000000; s_producer_thread_num = 1; s_consumer_thread_num = 1; s_count_push = 0; s_count_pop = 0; pthread_t prod, cons; pthread_create(&prod, nullptr, yqueue_producer_thread, nullptr); pthread_create(&cons, nullptr, yqueue_consumer_thread, nullptr); pthread_join(prod, nullptr); pthread_join(cons, nullptr); return 0; } 这里的 last_value = value;是什么意思?
11-08
void CHyNoteConfigBack::CreateTable() { const char* path = DbFilePath_; int rc = sqlite3_initialize(); if (rc != SQLITE_OK) { // 没有正确初始化分配内存 return; } sqlite3* db = NULL; // 数据库的指针 CHECKZERO(sqlite3_open(path, &db)); CHECKZERO(sqlite3_exec(db, "PRAGMA synchronous = OFF", 0, 0, 0)); char* errorrMsg = NULL; // 错误信息 CString createStr = _T("CREATE TABLE IF NOT EXISTS ") + TableName_ + _T("(id INTEGER PRIMARY KEY, 选项名称 TEXT,Value BLOB);"); char* createChStr = CStringToUtf8(createStr); int ret = sqlite3_exec(db, createChStr, 0, 0, &errorrMsg); if (ret == SQLITE_ERROR) { printf("ret:%d %s\n", ret, errorrMsg); sqlite3_free(errorrMsg); sqlite3_free(createChStr); CHECKZERO(sqlite3_close(db)); } // 执行准备 sqlite3_stmt* pPrepare = NULL; // 不存在就插入OR IGNORE 不存在就更新OR REPLACE CString InsertStr = _T("INSERT OR IGNORE INTO ") + TableName_ + _T("(id,选项名称,Value) VALUES (?,?,?);"); char* InsertChStr = CStringToUtf8(InsertStr); const char* sql = InsertChStr; CHECKZERO(sqlite3_prepare_v2(db, sql, strlen(sql), &pPrepare, 0)); CHECKZERO(sqlite3_exec(db, "BEGIN", 0, 0, 0)); DWORD startTime, endTime; startTime = GetTickCount(); CHECKZERO(sqlite3_reset(pPrepare)); CString str; int lastInsertRowId = sqlite3_last_insert_rowid(db); // 分配足够的缓冲区 size_t bufferSize = 1024; // 假设缓冲区大小为 1024 字节 char* buffer = new char[bufferSize]; size_t offset = 0; // 先将结构体转换为二进制数据 if (this->TextConfigSetupRegToBinary(data_, buffer, bufferSize, offset)) { acutPrintf(_T("\n Conversion to binary successful.")); } else { acutPrintf(_T("\n Conversion to binary failed.")); } int idx = 1; // 将注记类型值绑定到相应的参数上 CHECKZERO(sqlite3_bind_int(pPrepare, 1, idx)); CHECKZERO(sqlite3_bind_text(pPrepare, 2, CStringToUtf8(data_.OptionName), -1, SQLITE_STATIC)); sqlite3_bind_blob(pPrepare, 3, &buffer, offset, SQLITE_STATIC); int err = sqlite3_step(pPrepare); assert(SQLITE_DONE == err); sqlite3_reset(pPrepare); CHECKZERO(sqlite3_exec(db, "COMMIT", 0, 0, 0)); CHECKZERO(sqlite3_finalize(pPrepare)); // 释放 // 导出 //CHECKZERO(sqlite3_exec(db, "VACUUM INTO 'out.db3';", 0, 0, 0)); sqlite3_free(errorrMsg); sqlite3_free(createChStr); CHECKZERO(sqlite3_close(db)); delete[] buffer; endTime = GetTickCount() - startTime; acutPrintf(_T("\n 写入数据库用时 : %d 毫秒"), endTime); } 根据创建的代码用c++写出搜索函数,不要使用callback方式
最新发布
11-29
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值