'Develop > DB' 카테고리의 다른 글
Mysql 두 개의 테이블(또는 자신)에서 다른 값(불일치) 찾기 (0) | 2019.08.26 |
---|---|
[mysql] 쿼리시 스트링을 수타입으로 정렬하기 (0) | 2019.04.11 |
mysql 사용자 정의 변수 사용 (0) | 2018.07.13 |
only_full_group_by 에러 해결 (0) | 2018.07.04 |
그룹별 개수 조회 by 초 단위 (0) | 2018.05.30 |
Mysql 두 개의 테이블(또는 자신)에서 다른 값(불일치) 찾기 (0) | 2019.08.26 |
---|---|
[mysql] 쿼리시 스트링을 수타입으로 정렬하기 (0) | 2019.04.11 |
mysql 사용자 정의 변수 사용 (0) | 2018.07.13 |
only_full_group_by 에러 해결 (0) | 2018.07.04 |
그룹별 개수 조회 by 초 단위 (0) | 2018.05.30 |
mysql
+그룹별로 처음 나오는 하나의 줄만 뽑아낼때
ex) CAT_ID가 같은 것들끼리 묶어서 그룹별 처음으로 나온 레코드만 그룹 대표로 하나씩 추출한다.
select * from TABLE_A group by CAT_ID ;
그룹 내에서 어떤 키로 소팅하여 최신 값을 뽑는 경우, min, max 함수등을 이용하거나 미리 order by로 정렬 후 group by로 한다.
ex)
select * from (select * from TABLE_A order by NAME desc) a group by a.CAT_ID ;
select CAT_ID, min(NAME) from TABLE_A group by CAT_ID ;
+ group by 에러
only_full_group_by 에러가 발생.
=> mysql 5.7이상 부터 group by로 select 할 때 다른 값들이 있는 컬럼들을 조회하면 에러 발생.
처음 나온 것들을 자동으로 선택하여 조회하게 하려면 서버 설정을 바꿔주어야 한다.
/etc/mysql/my.cnf
[mysqld]
sql_mode=STRICT_TRANS_TABLES,NO_ENGINE_SUBSTITUTION
위와 같이 설정을 추가하여 서비스 재시작
service mysql restart
Mysql 두 개의 테이블(또는 자신)에서 다른 값(불일치) 찾기 (0) | 2019.08.26 |
---|---|
[mysql] 쿼리시 스트링을 수타입으로 정렬하기 (0) | 2019.04.11 |
mysql 사용자 정의 변수 사용 (0) | 2018.07.13 |
mysql select 한 데이터를 insert/update하기 (0) | 2018.07.12 |
그룹별 개수 조회 by 초 단위 (0) | 2018.05.30 |
cpp numerics library
수치 라이브러리
일반 수학 함수들은 <cmath> 헤더에 선언되어 있고 std::sin, std::sqrt 등으로 사용할 수 있다. 네임스페이스는 std를 사용.
복소수는 <complex> 헤더, 알고리즘은 <numeric> 헤더를 사용한다.
++Common mathematical functions
+abs(value) ; 절대값. 데이터 타입은 int, long, long long, float을 지원한다.
타입을 명시한 함수도 있다. fabs(float), labs(long) , llabs(long long) (C++11)
+div(x, y) ; 몫과 나머지를 구한다.
std::div_t div(int x, int y) ; 데이터 타입은 long, long long도 지원. ldiv(), lldiv() 사용.
struct div_t { int quot; int rem; } ; 리턴값인 div_t 타입은 몫과 나머지 필드가 있다.
itoa 함수 구현 예제
std::string itoa(int n, int base) {
std::string buf ;
std::div_t dv{} ;
dv.quot = n ;
do {
dv = std::div(dv.quot, base) ;
buf += "0123456789abcdef"[std::abs(dv.rem)] ;
} while (dv.quot) ;
if (n<0) buf +='-' ;
return { buf.rbegin(), buf.rend() } ;
}
+큰값, 작은값
max(a,b), fmax(a,b) 등. max는 int, long, long long, fmax는 float, double, long double
min(a,b), fmin(a,b) 등
+오차
fdim(a,b) ; a-b 값이 0보다 크면 a-b값을 리턴. 그렇지 않으면 0리턴. (dim 은 없다. fdim 사용 )
+지수, 로그
exp(arg) ; 자연상수 e의 arg승수 값. e^arg. 타입은 float, double, long double
exp2(arg) ; 2^arg (C++11)
log (arg) ; ln(arg) 자연로그
log10(arg) ; 밑이 10인 로그
pow(x, y) ; x^y
sqrt(x) ; root(x)
+삼각함수
sin, cos, tan, asin, acos, atan
const double pi = std::acos(-1) ;
std::sin( pi/6 ) --> 0.5
std::sin( pi/2 ) --> 1
2 * std::atan( INFINITY ) --> 3.14159 (pi)
atan2(y, x) ; atan ( y/x ), -pi~pi 범위의 리턴값
hyperbolic 삼각함수 ; sinh, cosh, tanh, asinh, acosh, atanh
sinh(arg) ; ( e^arg - e^-arg ) / 2
cosh(arg) ; ( e^arg + e^-arg ) / 2
tanh(arg) ; sinh / cosh
+ 가까운 정수
ceil ; 올림
floor ; 내림
round ; 반올림 (C++11)
float round(float arg) ; double round (double arg) ; ... long double 등.
libcurl HTTP POST send 모듈/curl 커맨드 방식도 지원 (0) | 2018.07.13 |
---|---|
if or 비교시 어떤 식의 성공으로 진입했는지 구분 (0) | 2018.07.13 |
Preprocessor (0) | 2018.06.20 |
deque (0) | 2018.06.13 |
stack / queue (0) | 2018.06.12 |
cpp preprocessor (전처리기)
전처리기는 소스코드를 컴파일 전단계 (translation phase)에서 처리된다. (런타임이 아니다.) 전처리가 된 후 컴파일러로 전달된다.
+지시어
#으로 시작한다.
키워드로는 define, undef, include, if, ifdef, ifndef, else, elif, endif, line, error, pragma 가 있다.
null 지시어로 #만 쓰는 것도 가능하다. (아무일도 안 함.)
+기능
전처리기는 소스 파일의 번역을 한다.
소스의 일부를 조건에 따라 컴파일할 수 있다. (#if, #ifdef, #ifndef, #else, #elif, #endif)
텍스트를 변경하는 매크로 기능을 한다. (텍스트를 붙이거나 식별자를 스트링으로 사용하는 등) (#define, #undef, 오퍼레이터로써 # , ## )
다른 파일들을 포함시킬 수 있다. (#include)
에러를 발생시킬 수 있다. (#error)
파일명과 라인 번호 정보를 알 수 있다. ( #line )
지정된 방식으로 작업을 한다. (#pragma)
+조건적 포함
#if [expression]
#ifdef [identifier]
#ifndef [identifier]
#elif [expression]
#else
#endif
조건에 따라 코드 블록이 수행된다.
#if, #elif 뒤에 나오는 expression은 상수적 표현을 의미한다. unary 연산자를 포함할 수 있고, defined identifier 나 defined (identifier) 를 사용할 수 있다.
expression의 값이 non-zero이면 해당 블록이 처리되고, 0이면 스킵된다.
#ifdef, #ifndef는 다음과 같다. (identifer가 매크로명으로 정의되었는지 검사한다.)
#if defined identifier
#if !defined identifier
#define ABCD 2
#include <iostream>
int main()
{
#ifdef ABCD
std::cout << "1: yes\n" ;
#else
std::cout << "1:no\n" ;
#endif
#ifndef ABCD
std::cout << "2:no1\n" ;
#elif ABCD==2
std::cout << "2.yes\n" ;
#else
std::cout << "2.no2\n" ;
#endif
#if !defined(DCCA) && (ABCD < 2*4-3)
std::cout << "3. yes\n" ;
#endif
}
모두 yes가 출력됨.
+텍스트 변경 매크로
#define identifier replacement-list
#define identifier(parameters) replacement-list
#define identifier(parameters, ...) replacement-list (C++11)
#define identifier(...) replacement-list (C++11)
#undef identifier
#define은 지정한 식별자를 replacement-list로 변경해 준다.
객체같은 매크로 ; identifier를 replacement-list로 교체한다.
함수같은 매크로 ; 위와 같지만 추가적으로 파라미터를 사용한다.
variable arguments의 경우 __VA_ARGS__ identifier를 사용한다.
__VA_OPT__(content)는 __VA_ARGS__가 비어 있지 않을 경우 확장된다.
#define F(...) f(0 __VA_OPT__(,) __VA_ARGS__)
F(1,2,3) --> f(0, 1,2,3)
F() --> f(0)
#define G(X, ...) f(0, X __VA_OPT__(,) __VA_ARGS__ )
G(a,b,c) --> f(0, a,b,c)
G(a,) --> f(0, a)
G(a) --> f(0, a)
#define SDEF(sname, ...) S sname __VA_OPT__(= {__VA_ARGS__} )
SDEF(foo); --> S foo;
SDEF(x, 1,2,3); --> S x = {1,2,3};
오퍼레이터 #, ##
함수같은 매크로에서 replacement-list 내부에서 식별자 앞에 # 오퍼레이터를 붙이면 결과를 ""로 묶게 된다. 내부에 "가 있으면 \도 자동으로 추가된다.
#define showlist(...) puts(#__VA_ARGS__)
showlist() ; --> puts("") ;
showlist(1,"x", int); --> puts("1, \"x\", int") ;
repplacement-list 내부에 연속된 두 개의 식별자 사이에 ## 오펴레이터가 추가되면 파라미터들을 두 식별자로 바꾸게 된다. 이 작업은 스트링을 붙여서 인식하게 된다.
#define Func(x) Func ##x
Func(1) --> Func1
Func(2) --> Func2
#include <iostream>
#define FUNC(name, val) int FUNC_##name() { return val ; }
FUNC(aaa, 10)
FUNC(bbb, 20)
FUNC(ccc, 30)
int main() {
std::cout << FUNC_aaa() << std::endl ;
std::cout << FUNC_bbb() << std::endl ;
std::cout << FUNC_ccc() << std::endl ;
return 0 ;
}
10, 20, 30이 출력된다.
FUNC(aaa, 10) --> int FUNC_aaa() { return 10 ; }
위와 같이 풀린다.
+ Predefined macro
__FILE__ ; 현재 소스 파일명으로 확장 (string)
__LINE__ ; 현재 라인 번호 (int)
__DATE__ ; 컴파일 날짜(translation date) "Mmm dd yyyy"
__TIME__ ; 컴파일 시간 "hh:mm:ss"
#include <filename>
#include "filename"
해당 파일을 그 위치에 포함시킨다.
C, C++ 라이브러리는 표준 include디렉터리에서 불러들인다. (include 디렉터리는 컴파일 옵션으로 설정할 수 있다.)
""로 지정하면 소스파일의 디렉터리에서 검색한다. 못찾으면 표준 include 디렉터리에서 찾는다.
nested된 include에 의해 반복될 경우를 막기위해 다음과 같이 한 번한 include되게 한다.
#ifndef _FOO_H_
#define _FOO_H_
// to do..
#endif
pragma를 지원하는 컴파일러에서 아래와 같이 사용하면 위 효과를 동일하게 할 수 있다.
#pragma once
#error error_message
위 지시자를 만나면 에러 메시지를 출력한다. 컴파일 시점에서 발생한다.
#if !WINDOWS_XP && !WINDOWS_7
#error Please check your OS
#endif
#line lineno
#line lineno "filename"
다음 줄 라인 번호를 lineno로 변경한다. 매크로 __LINE__ 값이 바뀐다.
뒤에 파일명을 주면 __FILE__ 매크로인 파일명이 바뀐다.
#line 777 "test.cc"
assert(2+2==5) ;
위 소스를 컴파일 할 경우, test.cc:777 에서 assertion 에러가 발생한다.
if or 비교시 어떤 식의 성공으로 진입했는지 구분 (0) | 2018.07.13 |
---|---|
Numerics library (0) | 2018.06.21 |
deque (0) | 2018.06.13 |
stack / queue (0) | 2018.06.12 |
cstring (0) | 2018.06.11 |
cpp deque
include <deque>
double ended queue . 입출구가 양쪽 끝에 달린 형태.
++Iterators
begin, end, rbegin, rend, cbegin, cend, crbegin, crend
++capacity
size, max_size, resize, empty, shrink_to_fit
++elements access
[], at, front, back
++modifiers
assign, push_back, push_front, pop_back, pop_front
insert, erase, swap, clear, emplace, emplace_front, emplace_back
ex)
std::deque<int> myq (2, 100) ; // 100을 값으로 2개 노드 생성.. 100,100
myq.push_front(200) ; // 200,100,100
myq.push_front(300) ; // 300,200,100,100
myq.push_back(99) ; // 300, 200,100,100, 99
std::cout << myq.front() << '\n' ; // 300
std::cout << myq.back() << '\n' ; // 99
myq.pop_front() ; // 200,100,100,99
myq.pop_back() ; // 200,100,100
// 출력
for (std::deque<int>::iterator it=myq.begin(); it!=myq.end(); ++it) {
std::cout<<' ' << *it ;
}
+insert
iterator insert(const_iterator pos, const value_type& val) ; // 지정된 위치에 삽입.
iterator insert( ", size_type n, const vlaue_type &val) ; // 지정된 위치에 해당 값을 n개 삽입. (fill)
iterator insert(", InputIterator first, last) ; // 지정한 위치에 범위를 삽입.
iterator insert(", initializer_list<value_type> il) ;
리턴값은 새로 추가된 첫번째 엘리먼트의 위치
std::deque<int> myq ;
for (int i=1; i<6; i++) myq.push_back(i); // 1 2 3 4 5
std::deque<int>::iterator it = myq.begin() ; // it point 1
++it ; // next position ; it point 2
it = myq.insert(it, 10) ; // 1 10 2 3 4 5
myq.insert(it, 2, 20); // 1 20 20 10 2 3 4 5
+erase
지정된 위치 또는 범위를 삭제.
리턴값은 삭제된 범위에 처음 오게 될 요소의 위치.
myq.erase( myq.begin()+3) ;
myq.erase( myq.begin(), myq.begin()+3) ;
Numerics library (0) | 2018.06.21 |
---|---|
Preprocessor (0) | 2018.06.20 |
stack / queue (0) | 2018.06.12 |
cstring (0) | 2018.06.11 |
thread mutex (0) | 2018.06.10 |
cpp stack
include <stack>
LIFO로 디자인된 자료구조. push/pop
+ member functions
empty ; 비었는지 테스트
size ; 스택 엘리먼트 개수
top ; 가장 위의 엘리먼트 접근
push ; 삽입. (가장 위에 추가)
emplace(c++11) ; construct & push
pop ; top(가장 위) 엘리먼트를 제거
swap(c++11) ; 다른 스택과 바꿈.
+ex)
std::stack<int> st1 ;
st1.push(1) ;
st1.push(2) ;
st1.push(3) ;
st1.size() // => size=3
st1.top() // => 3
st1.pop() // => size=2
st1.top() // => 2
st1.empty() // => false
while( !st1.empty() ) { // 일반적인 스택 데이터를 전부 하나씩 추출하는 방법.
std::cout << ' ' << st1.top() ; // 최상위 노드 접근.
st1.pop() ; // 최상위 노드 삭제.
}
+ swap ex)
std::stack<int> foo, bar ;
foo.push(10); foo.push(20); foo.push(30) ;
bar.push(11) ; bar.push(22) ;
foo.swap(bar) ; // foo와 bar가 바뀜.
foo.size() ; // 2
bar.size() ; // 3
++ queue
FIFO 방식의 자료구조
include <queue>
+members
empty
size
front ; 가장 앞 노드의 값
back ; 가장 뒤 노드의 값
push ; 노드를 가장 뒤에 추가
emplace (c++11)
pop ; 가장 앞의 노드를 제거
swap (c++11)
ex)
std::queue<int> q1 ;
q1.push(1) ;
q1.push(2) ;
q1.push(3) ;
while( !q1.empty() ) {
std::cout << ' ' << q1.front() ; // 가장 앞 노드값 출력
q1.pop() ; // 가장 앞 노드 제거.
}
Preprocessor (0) | 2018.06.20 |
---|---|
deque (0) | 2018.06.13 |
cstring (0) | 2018.06.11 |
thread mutex (0) | 2018.06.10 |
thread (0) | 2018.06.09 |
cpp cstring
c string and array
include <cstring>
+함수들
void * memcpy (void *dest, const void *src, size_t num) ; dest return.
void * memmove(void *dest, const void *src, size_t num) ; memcpy와 유사하나 차이점은 dest와 src가 overlap이 되어도 된다. 따라서 성능상은 memcpy가 더 좋음. 그러나 overlap이 필요하면 memmove를 사용한다.
char* strcpy(char *dest, const char *src) ; dest return. null 문자까지 복사.
char* strncpy(char *dest, const char *src, size_t num) ; num크기까지 복사한다. num전에 null문자가 있으면 null전까지 복사하고 나머지는 null로 패딩한다.
char* strcat (char *dest, const char *src) ; src문자를 dest뒤에 붙인다. dest return.
char* strncat (char *dest, const char *src, size_t num) ; src의 num 크기만큼만 dest 뒤에 붙인다. 마지막에 null문자 추가.
int memcmp (const void *ptr1, const void *ptr2, size_t num) ; 두 메모리 블록을 비교한다. strcmp와 다르게 null문자가 있어도 중간에 멈추지 않고 지정된 크기만큼 비교한다. return ; ptr1<ptr2 이면 <0, ptr1>ptr2이면 >0 , ptr1=ptr2 이면 0.
int strcmp (const char *str1, const char *str2) ; 두 스트링을 비교한다. return ; <0, >0, 0
int strncmp(", ", size_t num)
등
char * strchr( char *str, int ch) ; 스트링에서 지정한 문자를 찾아 위치를 리턴.
char* strrchr (char *str, int ch) ; 스트링에서 지정한 문자를 뒤에서 부터 찾아 위치를 리턴.
char* strstr (char *str1, const char *str2) ; str1 스트링에서 str2 스트링을 찾아 위치를 리턴.
char* strtok (char *str, const char *delimeters) ; 스트링을 토크닝함. 딜리미터로 지정된 문자열 가운데 아무 문자나 맞으면 자른다. 다음 토큰 검색시에는 str을 NULL로 준다. 주의! thread-unsafe! . thread에서는 strtok_r() 사용.
void* memset (void *ptr, int val, size_num) ; 메모리 블록을 특정 값으로 초기화. ptr is returned.
size_t strlen(const char *str) ; 스트링 길이를 리턴.
+잘 안쓰는 함수
void * memchr(void *ptr, int val, size_num) ; 메모리 블록에서 지정된 값을 찾는다. return ; 처음 val이 발견된 주소. 없으면 null
size_t strcspn (const char *str1, const char *str2) ; str1에서 str2의 임의의 문자가 가장 먼저 나오는 곳 이전까지의 길이. str2를 any delimeter로 보고 첫 번째 토큰의 길이.
char * strpbrk (char *str1, const char *str2) ; str2를 any delimeter로 보고 처음 나오는 delimeter의 위치 포인터 리턴.
char* strerror(int errnum) ; 에러코드를 에러스트링으로 변환.
deque (0) | 2018.06.13 |
---|---|
stack / queue (0) | 2018.06.12 |
thread mutex (0) | 2018.06.10 |
thread (0) | 2018.06.09 |
utility (0) | 2018.06.08 |
cpp mutex
include <mutex>
+ mutex 사용하기
std::mutex mtx ;
void func(int id, int &v) {
for (int i=0; i<10; i++) {
mtx.lock() ;
++v ;
mtx.unlock() ;
}
}
int v=0 ;
std::thread t1 (func, 0, std::ref(v) ) ;
std:;thread t2(func, 1, std::ref(v) ) ;
t1.join();
t2.join() ;
-lock() ; 다른 쓰레드에 의해 lock되어 있지 않는 경우, 현재 쓰레드에서 락을 건다. unlock을 할 때까지 현재 쓰레드가 뮤텍스를 소유함.
이미 다른쓰레드가 뮤텍스를 소유하고 있으면, 해제될때까지 블로킹 된다.
- lock을 얻은 상태에서 또 lock()을 하면 안된다. 데드락 발생. (중복 lock을 하려면 recursive_mutex 사용)
+ bool try_lock() ; lock을 얻지 못하면 바로 리턴한다. 블로킹되지 않는 것이 lock()과 차이.
뮤텍스를 얻었으면 true를 리턴하고, 작업 완료시 unlock()을 해주어야 한다.
다른 쓰레드가 뮤텍스 소유하고 있으면 false를 바로 리턴한다.
+ recursive_mutex ; mutex와 비슷하나, lock 등급이 가능.
락을 얻은 상태에서 또 락을 얻을 수 있다. 뮤텍스 소유 레벨을 올림.
나중에 unlock()을 lock() 횟수만큼 해줘야 한다.
==> Mutex를 직접사용하지 말고 아래(lock_guard, unique_lock) 를 사용하기를 권장함.
+ lock_guard ; 함수 내부에서 사용하여 간단하게 동기화 처리.
내부적으로 mutex를 사용하여 항상 락이 되도록 유지.
constructor에서 락을 얻고, destructor에서 언락을 한다.
std::mutex mtx ;
void func(int id) {
try {
std::lock_guard<std::mutex> lck(mtx) ;
} catch ( std::logic_error & ) {
}
}
+unique_lock ; 뮤텍스를 사용하여 동기화 처리. lock_guard와 비슷하나 구동 시점을 지정할 수 있다.
lock, unlock을 사용 가능하며, 굳이 사용 안 해도 lock_guard 처럼 작동한다.
함수 일부분내에서 동기화 해제해도 되는 구간이 있을 경우에 사용하면 될 것 같다.
생성시점에 락을 안 걸 수도 있다.
guard(mutex, std::defer_lock) ; 이렇게 초기화하면 락을 얻지 않는다.
stack / queue (0) | 2018.06.12 |
---|---|
cstring (0) | 2018.06.11 |
thread (0) | 2018.06.09 |
utility (0) | 2018.06.08 |
fstream 1 basic_ifstream (0) | 2018.06.07 |
cpp thread
include <thread>
+간단한 thread 예
void func() { cout << "aaa" << endl ; }
thread t(&func) ; // func함수가 쓰레드로 실행.
t.join() ; // thread t가 종료 될때 까지 기다림.
+ thread 함수에 파라미터 주기
void func(int x) {..} ;
thread t1(&func, 10) ;
thread t2(&func, 20) ;
t1.join() ;
t2.join() ;
+global 변수를 다중 thread로 카운팅하기
std::atomic<int> global_cnt(0) ; // atomic 하게 작업.
void increase_global(int n) {
for (int i=0; i<n; i++) ++global_cnt;
}
std::vector<std::thread> threads ;
for (int i=0; i<5; i++)
threads.push_back( std::thread( increase_global, 100) ) ;
// 5개의 쓰레드로 100번씩 돌림. global_cnt=>500
+다른 방식
void increase_ref(std::atomic<int> &v , int n) {
for (int i=0; i<n; i++) ++v;
}
std::atomic<int> foo(0) ;
for (int i=0; i<5; i++)
threads.push_back( std::thread( increase_ref, std::ref(foo), 100) ) ;
cstring (0) | 2018.06.11 |
---|---|
thread mutex (0) | 2018.06.10 |
utility (0) | 2018.06.08 |
fstream 1 basic_ifstream (0) | 2018.06.07 |
functional 1 plus,minus,bind1st, bind2nd, equal_to, greater (0) | 2018.06.07 |
cpp utility
include <utility>
+swap ; 두 객체의 값들을 바꾼다.
int x=10, y=20 ;
std::swap(x,y) ; // x=20, y=10
int foo[4] ;
int bar[]={1,2,3,4} ;
std::swap(foo, bar) ; // foo=1,2,3,4
+make_pair ; 두 객체를 pair로 만들어 리턴한다. 타입이 맞지 않으면 알아서 컨버팅 해준다.
std::pair<int,int> foo ;
foo = std::make_pair(10,20) ;
// access value: foo.first, foo.second
thread mutex (0) | 2018.06.10 |
---|---|
thread (0) | 2018.06.09 |
fstream 1 basic_ifstream (0) | 2018.06.07 |
functional 1 plus,minus,bind1st, bind2nd, equal_to, greater (0) | 2018.06.07 |
algorithm 4 merge, heap, min, max (0) | 2018.06.06 |