Restructure cats and tags

This commit is contained in:
thomasabishop 2022-08-16 11:58:34 +01:00
parent f59ed32b9c
commit 0a740ddb65
32 changed files with 392 additions and 428 deletions

View file

@ -1,10 +1,9 @@
---
tags:
- Algorithms_Data_Structures
tags: [algorithms]
---
![Screenshot_2021-05-11_at_18.55.23.png](../img/Screenshot_2021-05-11_at_18.55.23.png)
*Summary of the main classes of algorithmic complexity*
_Summary of the main classes of algorithmic complexity_
## Distinguish algorithms from programs
@ -19,12 +18,11 @@ If we are landing the Curiosity Rover on Mars we may choose an algorithm that is
We need a generalised measure of efficiency to compare algorithms, across variant hardware. We can't simply use the number of steps, since some steps will be quicker to complete than others in the course of the overall algorithm and may take longer on different machines. Moreover the same algorithm could run at different speeds on the same machine, depending on its internal state at the given time that it ran. So we use the following: **the number of steps required relative to the input.**
>
> Two given computers may differ in how quickly they can run an algorithm depending on clock speed, available memory and so forth. They will however tend to require approximately the same number of instructions and we can measure the rate at which the number of instructions increases with the problem size.
> Two given computers may differ in how quickly they can run an algorithm depending on clock speed, available memory and so forth. They will however tend to require approximately the same number of instructions and we can measure the rate at which the number of instructions increases with the problem size.
This is what **asymptotic runtime** means: the rate at which the runtime of an algorithm grows compared to the size of its input. For precision and accuracy we use the worst case scenario as the benchmark.
So: the efficiency of algorithm *A* can be judged relative to the efficiency of algorithm *B* based on the rate at which the runtime of *A* grows compared to its input, compared to the same property in *B*, assuming the worst possible performance.
So: the efficiency of algorithm _A_ can be judged relative to the efficiency of algorithm _B_ based on the rate at which the runtime of _A_ grows compared to its input, compared to the same property in _B_, assuming the worst possible performance.
From now on we will use the word 'input' to denote the data that the algorithm receives (in most cases we will envision this as an array containing a certain data type) and 'execution' to denote the computation that is applied by the algorithm to each item of the data input. Rephrasing the above with these terms we can say that 'algorithmic efficiency' is a measure that describes the rate at which the execution time of an algorithm increases relative to the size of its input.
@ -38,7 +36,7 @@ Let's start with linear time, which is the easiest runtime to grasp.
We need an example to make this tangible and show how an algorithm's runtime changes compared to the size of its input. Let's take a simple function that takes a sequence of integers and returns their sum:
````js
```js
function findSum(arr){
let total = 0;
for (let i = 0; i < arr.length; i++){
@ -46,7 +44,7 @@ function findSum(arr){
)
return total
}
````
```
The input of this function is an array of integers. It returns their sum as the output. Let's say that it takes 1ms for the function to sum an array of two integers.
@ -60,12 +58,12 @@ A more general way to say this is that the runtime is equal to size of the input
If we say that it takes 1ms for two integers to be summed, this gives us the following data set:
|Length of input|Runtime|
|:--------------|------:|
|2|2|
|3|3|
|4|4|
|5|5|
| Length of input | Runtime |
| :-------------- | ------: |
| 2 | 2 |
| 3 | 3 |
| 4 | 4 |
| 5 | 5 |
If we plotted this as a graph it is clear that this is equivalent to a linear distribution:![lin.svg](../img/lin.svg)
@ -79,20 +77,17 @@ We can now introduce notation to formalise the algorithmic properties we have be
To express linear time algorithms formally, we say that:
>
> it takes some constant amount of time ($C$) to sum one integer and n times as long to sum n integers
> it takes some constant amount of time ($C$) to sum one integer and n times as long to sum n integers
Here the constant is the time for each execution to run and n is the length of the input. Thus the complexity is equal to that time multiplied by the input.
The algebraic expression of this is $cn$ : the constant multiplied by the length of the input. In algorithmic notation, the reference to the constant is always removed. Instead we just use n and combine it with a 'big O' which stands for 'order of complexity'. Likewise, if we have an array of four integers being passed to `findSum` we could technically express it as O(4n), but we don't because we are interested in the general case not the specific details of the runtime. So a linear algorithm is expressed algebraically as $O(n)$ which is read as "oh of n" and means
>
> $O(n)$ = with an order of complexity equal to (some constant) multiplied by n
> $O(n)$ = with an order of complexity equal to (some constant) multiplied by n
Applied, this means an input of length 6 ($n$) where runtime is constant ($c$) at 1ms has a total runtime of 6 x 1 = 6ms in total. Exactly the same as our table and graph. O n is just a mathematical way of saying *the runtime grows on the order of the size of the input.*
Applied, this means an input of length 6 ($n$) where runtime is constant ($c$) at 1ms has a total runtime of 6 x 1 = 6ms in total. Exactly the same as our table and graph. O n is just a mathematical way of saying _the runtime grows on the order of the size of the input._
>
> It's really important to remember that when we talk about the execution runtime being constant at 1ms, this is just an arbitrary placeholder. We are not really bothered about whether it's 1ms or 100ms: 'constant' in the mathematical sense doesn't mean a unit of time, it means 'unchanging'. We are using 1ms to get traction on this concept but the fundamental point being expressed is that the size of the input doesn't affect the execution time across the length of the execution time.
> It's really important to remember that when we talk about the execution runtime being constant at 1ms, this is just an arbitrary placeholder. We are not really bothered about whether it's 1ms or 100ms: 'constant' in the mathematical sense doesn't mean a unit of time, it means 'unchanging'. We are using 1ms to get traction on this concept but the fundamental point being expressed is that the size of the input doesn't affect the execution time across the length of the execution time.
## Constant time
@ -110,7 +105,7 @@ With the examples of constant and linear time, the total number of instructions
Let's start with an example.
````js
```js
const letters = ['A', 'B', 'C'];
function quadratic(arr) {
@ -122,15 +117,15 @@ function quadratic(arr) {
}
quadratic(letters);
````
```
This function takes an array . The outer loop runs once for each element of the array that is passed to the function. For each iteration of the outer loop, the inner loop also runs once for each element of the array.
In the example this means that the following is output:
````
```
A A A B B B C C C (length: 9)
````
```
Mathematically this means that n (the size of the input) grows at a rate of n2 or the input multiplied by itself. Our outer loop (`i`) is performing n iterations (just like in linear time) but our inner loop (`j`) is also performing n iterations, three `j`s for every one `i` . It is performing n iterations for every nth iteration of the outer loop. So runtime here is directly proportional to the squared size of the input data set. As the input array has a length of 3, and the inner array runs once for every element in the array, this is equal to 3 x 3 or 3 squared (9).
@ -151,14 +146,13 @@ $$ \log \_{2}8 = 3 \leftrightarrow 2^3 = 8 $$
When we use log in the context of algorithms we are always using the binary number system so we omit the 2, we just say log.
>
> With base two logarithms, the logarithm of a number roughly measures the number of times you can divide that number by 2 before you get a value that is less than or equal to 1
> With base two logarithms, the logarithm of a number roughly measures the number of times you can divide that number by 2 before you get a value that is less than or equal to 1
So applying this to the example of $\log 8$ , it is borne out as follows:
* 8 / 2 = 4 — count: 1
* 4 / 2 = 2 — count: 2
* 2 / 2 = 1 — count: 3
- 8 / 2 = 4 — count: 1
- 4 / 2 = 2 — count: 2
- 2 / 2 = 1 — count: 3
As we are now at 1, we can't divide any more, so $\log 8$ is equal to 3.
@ -166,18 +160,18 @@ Obviously this doesn't work so neatly with odd numbers, so we approximate.
For example, with $\log 25$:
* 25 / 2 = 12.5 — count: 1
- 25 / 2 = 12.5 — count: 1
* 12.5 / 2 = 6.25 — count: 2
- 12.5 / 2 = 6.25 — count: 2
* 6.25 / 2 = 3.125 — count: 3
- 6.25 / 2 = 3.125 — count: 3
* 3.125 / 2 = 1.5625 — count: 4
- 3.125 / 2 = 1.5625 — count: 4
- 1.5625 / 2 = 0.78125
* 1.5625 / 2 = 0.78125
Now we are lower than 1 so we have to stop. We can only say that the answer to $\log 25$ is somewhere between 4 and 5.
The exact answer is $\log 25 \approx 4.64$
Back to algorithms: $O(\log n)$ is a really good complexity to have. It is close to O(1) and in between O(1) and O(n). Represented graphically, it starts of with a slight increase in runtime but then quickly levels off:
@ -192,21 +186,21 @@ When we talk about big O we are looking for the most general case, slight deviat
For example, with the following function:
````js
function sumAndAddTwo(arr){
let total = 0;
for (let i = 0; i < arr.length; i++){
total += arr[i];
}
total = total+= 2;
```js
function sumAndAddTwo(arr) {
let total = 0;
for (let i = 0; i < arr.length; i++) {
total += arr[i];
}
total = total += 2;
}
````
```
The formal representation of the above complexity would be O(n) + O(1). But it's easier just to say O(n), since the O(1) that comes from adding two to the result of the loop, makes a marginal difference overall.
Similarly, with the following function:
````js
```js
function processSomeIntegers(integers){
let sum, product = 0;
@ -217,19 +211,19 @@ function processSomeIntegers(integers){
integers.forEach(function(int){
return product *= int;
}
console.log(`The sum is ${sum} and the product is ${product}`);
}
````
```
It might appear to be more complex than the earlier summing function but it isn't really. We have one array (`integers` ) and two loops. Each loop is of O(n) complexity and does a constant amount of work. If we add O(n) and O(n) we still have O(n), not O(2n). The constant isn't changed in any way by the fact that we are looping twice through the array in separate processes, it just doubles the length of n. So rather than formalising this as O(n) + O(n), we just reduce it to O(n).
When seeking to simplify algorithms to their most general level of complexity, we should keep in mind the following shorthands:
* Arithmetic operations always take constant time
* Variable assignment always takes constant time
* Accessing an element in an array by index or an object value by key is always constant
* in a loop the complexity is the length of the loop times the complexity of whatever happens inside of the loop
- Arithmetic operations always take constant time
- Variable assignment always takes constant time
- Accessing an element in an array by index or an object value by key is always constant
- in a loop the complexity is the length of the loop times the complexity of whatever happens inside of the loop
With this in mind we can break down the `findSum` function like so:
@ -249,8 +243,8 @@ Space complexity in this sense is called 'auxiliary space complexity'. This mean
Again there are some rules of thumb:
* Booleans, `undefined`, and `null` take up constant space
* Strings require O(n) space, where n is the sting length
* Reference types take up O(n): an array of length 4 takes up twice as much space as an array of length 2
- Booleans, `undefined`, and `null` take up constant space
- Strings require O(n) space, where n is the sting length
- Reference types take up O(n): an array of length 4 takes up twice as much space as an array of length 2
So with space complexity we are not really interested in how many times the function executes, if it is a loop. We are looking to where data is stored: how many variables are initialised, how many items there are in the array.

View file

@ -1,6 +1,5 @@
---
tags:
- Algorithms_Data_Structures
tags: [data-structures]
---
# Arrays

View file

@ -1,9 +1,10 @@
---
tags:
- Algorithms_Data_Structures
tags: [data-structures]
---
\_Visualization of the queue data structure _
# Queues
_Visualization of the queue data structure_
![queue.svg](../img/queue.svg)
@ -23,22 +24,21 @@ As we are removing the first element added, we use an `array shift` method to re
Removing an element from the queue is called **dequeuing**. Adding an element to the queue is called **enqueuing**. In terms of the tail/head nomenclature, the end of the queue where elements are enqueued is the **tail** and front of the queue, where elements are removed is the **head**.
````js
```js
class Queue {
items = [] // array to store the elements comprising the queue
enqueue = (element) => this.items.push(element) // add element to back
dequeue = () => this.items.shift() // remove element from the front
items = []; // array to store the elements comprising the queue
enqueue = (element) => this.items.push(element); // add element to back
dequeue = () => this.items.shift(); // remove element from the front
// Optional helper methods:
isEmpty = () => (this.items.length === 0) // return true if the queue is empty
clear = () => this.items.length = 0 // empty the queue
size = () => this.items.length // count elements in queue
peek = () => !this.isEmpty() ? this.items[0] : undefined; // check which element is next in line
// Optional helper methods:
isEmpty = () => this.items.length === 0; // return true if the queue is empty
clear = () => (this.items.length = 0); // empty the queue
size = () => this.items.length; // count elements in queue
peek = () => (!this.isEmpty() ? this.items[0] : undefined); // check which element is next in line
}
````
```
## Use cases
* A queue sequences data in the order that it was first received. Thus it is most beneficial in scenarios where receipt time is a factor. For example, imagine a service whereby tickets go on sale at a certain time for a limited period. You may want to prioritise those who sent their payment earliest over those who arrived later.
* Serving requests on a single shared resource like a printer or CPU task scheduling.
- A queue sequences data in the order that it was first received. Thus it is most beneficial in scenarios where receipt time is a factor. For example, imagine a service whereby tickets go on sale at a certain time for a limited period. You may want to prioritise those who sent their payment earliest over those who arrived later.
- Serving requests on a single shared resource like a printer or CPU task scheduling.

View file

@ -1,12 +1,8 @@
---
tags:
- Algorithms_Data_Structures
- recursion
tags: [algorithms, recursion]
---
>
> A recursive function is a function that calls itself in its definition.
> A recursive function is a function that calls itself in its definition.
More generally recursion means when a thing is defined in terms of itself. There are visual analogues that help to represent the idea such as the Droste effect where an image contains a version of itself within itself. The ouroboros is another example. Also fractals display recursive properties.
@ -23,97 +19,92 @@ Recursive programming differs from **iterative** programming but both have simil
## Base condition
>
> Once a condition is met, the function stops calling itself. This is called a base condition.
> Once a condition is met, the function stops calling itself. This is called a base condition.
Because recursion has the potential for infinity, to use it, we must specify a point at which it ends. However as we are not using an iterative approach we cannot rely on `while` or `foreach` to specify the boundaries of its operation. We call this the **base condition** and this will typically be specified using conditional logic.
The schema for a recursive function with a base condition is:
````jsx
```jsx
function recurse() {
if(condition) {
recurse();
}
else {
// stop calling recurse()
}
if (condition) {
recurse();
} else {
// stop calling recurse()
}
}
recurse();
````
```
## Demonstrations
### Countdown
````jsx
```jsx
// program to count down numbers to 1
function countDown(number) {
// display the number
console.log(number);
// display the number
console.log(number);
// decrease the number value
let newNumber = number - 1;
// decrease the number value
let newNumber = number - 1;
// base case
if (newNumber > 0) {
countDown(newNumber);
}
// base case
if (newNumber > 0) {
countDown(newNumber);
}
}
countDown(4);
````
```
* This code takes `4` as it's input and then outputs a countdown returning: `4, 3, 2, 1`
* In each iteration, the number value is decreased by 1
* The base condition is `newNumber > 0` . This breaks the recursive loop once the output reaches `1` and stops it continuing into negative integers.
- This code takes `4` as it's input and then outputs a countdown returning: `4, 3, 2, 1`
- In each iteration, the number value is decreased by 1
- The base condition is `newNumber > 0` . This breaks the recursive loop once the output reaches `1` and stops it continuing into negative integers.
Each stage in the process is noted below:
````
```
countDown(4) prints 4 and calls countDown(3)
countDown(3) prints 3 and calls countDown(2)
countDown(2) prints 2 and calls countDown(1)
countDown(1) prints 1 and calls countDown(0)
````
```
### Finding factorials
>
> The factorial of a positive integer **n** is the product of all the positive integers less than or equal to **n**.
> The factorial of a positive integer **n** is the product of all the positive integers less than or equal to **n**.
To arrive at the factorial of **n** you subtract 1 from **n** and multiply the result of the subtraction by **n**. You repeat until the subtractive process runs out of positive integers. For example, if 4 is **n,** the factorial of **n** is **24:**
$$ 4 * 3 * 2 \*1 $$
$$ 4 _ 3 _ 2 \*1 $$
4 multiplied by 3 gives you 12, 12 multiplied by 2 gives you 24. 24 multiplied by 1 is 24.
This is clearly a process that could be implemented with a recursive function:
````js
```js
// program to find the factorial of a number
function factorial(x) {
// if number is 0
if (x === 0) {
return 1;
}
// if number is 0
if (x === 0) {
return 1;
}
// if number is positive
else {
return x * factorial(x - 1);
}
// if number is positive
else {
return x * factorial(x - 1);
}
}
let num = 3;
// calling factorial() if num is non-negative
if (num > 0) {
let result = factorial(num);
console.log(`The factorial of ${num} is ${result}`);
let result = factorial(num);
console.log(`The factorial of ${num} is ${result}`);
}
````
```
![javascript-factorial 1.png](../img/javascript-factorial%201.png)

View file

@ -1,12 +1,11 @@
---
tags:
- Algorithms_Data_Structures
tags: [data-structures]
---
*A stack visualised vertically*
_A stack visualised vertically_
![stack2.svg](../img/stack2.svg)
*A stack visualised horizontally*
_A stack visualised horizontally_
![stack1.svg](../img/stack1.svg)
## A stack is a linear data structure that observes LIFO
@ -25,39 +24,39 @@ A stack is an example of a data structure that can be built by adapting an array
Below we create a stack constructor, using a class. An object created from this template will have the following properties and methods:
* `items[]` → an array to store the data
* `push()` → a method to add an element to the end of the stack
* `pop()` → a method to remove an element from the front
- `items[]` → an array to store the data
- `push()` → a method to add an element to the end of the stack
- `pop()` → a method to remove an element from the front
In addition we have the following helpers, which allow us to check the status of the stack and retrieve information about it:
* `isEmpty()` → check if the stack is populated or not
* `clear()` → empty the stack of its content (therefore making `isEmpty()` return `true`)
* `size` → a property corresponding to the stack's length
- `isEmpty()` → check if the stack is populated or not
- `clear()` → empty the stack of its content (therefore making `isEmpty()` return `true`)
- `size` → a property corresponding to the stack's length
````js
```js
class Stack {
items = [] // the array that will store the elements that comprise the stack
push = (element) => this.items.push(element) // add an element to the end of the stack
pop = () => this.items.pop() // remove and return the last element from the stack
items = []; // the array that will store the elements that comprise the stack
push = (element) => this.items.push(element); // add an element to the end of the stack
pop = () => this.items.pop(); // remove and return the last element from the stack
// We can add some useful helper methods, that return info about the state of the stack:
isEmpty = () => (this.items.length === 0) // return true if the stack is empty
clear = () => this.items.length = 0 // empty the stack
size = () => this.items.length // count elements in stack
isEmpty = () => this.items.length === 0; // return true if the stack is empty
clear = () => (this.items.length = 0); // empty the stack
size = () => this.items.length; // count elements in stack
}
````
```
## Run through
````js
```js
let stack = new Stack();
test.push(1); // Add some elements to the stack
test.push(2);
test.push(3);
// Stack now looks like:
console.log(stack.items); // [1, 2, 3]
console.log(stack.items); // [1, 2, 3]
// Let's try removing the last element
stack.pop(); // 3 -> this was the last element we added, so it's the first one that comes out
@ -66,14 +65,14 @@ stack.pop(); // 3 -> this was the last element we added, so it's the first one t
// [1,2]
// Let's add a new element
test.push(true)
test.push(true);
// Now the stack looks like:
// [1,2, true]
````
```
## Practical applications
* Any application that wants to got 'back in time' must utilise a stack. For example, the 'undo' function in most software is a function of a stack. The most recent action is at the top, and under that is the second most recent and so on all the way back to the first action.
* Recursive functions: a function that calls itself repeatedly until a boundary condition is met is using a stack structure. As you drill down through the function calls you start from the most recent down to the last.
* Balancing parentheses. Say you want to check if the following string is balanced `[()]` . Every time you find an opening parentheses. You push that to the front of a stack. You then compare the closing parentheses with the order of the stack. The same could be done when seeking to find palindromes. This sort of thing could be a code challenge so build an example.
- Any application that wants to got 'back in time' must utilise a stack. For example, the 'undo' function in most software is a function of a stack. The most recent action is at the top, and under that is the second most recent and so on all the way back to the first action.
- Recursive functions: a function that calls itself repeatedly until a boundary condition is met is using a stack structure. As you drill down through the function calls you start from the most recent down to the last.
- Balancing parentheses. Say you want to check if the following string is balanced `[()]` . Every time you find an opening parentheses. You push that to the front of a stack. You then compare the closing parentheses with the order of the stack. The same could be done when seeking to find palindromes. This sort of thing could be a code challenge so build an example.

View file

@ -1,30 +1,28 @@
---
tags:
categories:
- Databases
---
# Fundamental database concepts
> A database is a collection of organised data that can be efficiently stored, sorted, and searched.
> A database is a collection of organised data that can be efficiently stored, sorted, and searched.
How the data is organised will often determine the *type* of database used. There are many different types of database; some examples of the different types are relational, object-orientated, graphical, NoSQL, and distributed.
How the data is organised will often determine the _type_ of database used. There are many different types of database; some examples of the different types are relational, object-orientated, graphical, NoSQL, and distributed.
## ACID principle
To ensure the integrity of a database, each change or transaction must conform to a set of rules known as ACID:
* **atomicity**
* when changing data within a database, if any part of the change fails, the whole change will fail and the data will remain as it was before the change was made; this is a safeguard that prevents partial records being created.
* **consistency**
* before data can be changed in a database, it must be validated against a set of rules
* **isolation**
* databases allow multiple changes at the same time, but each change is isolated from others
* **durability**
* once a change has been made, the data is safe, even in the event of system failure
- **atomicity**
- when changing data within a database, if any part of the change fails, the whole change will fail and the data will remain as it was before the change was made; this is a safeguard that prevents partial records being created.
- **consistency**
- before data can be changed in a database, it must be validated against a set of rules
- **isolation**
- databases allow multiple changes at the same time, but each change is isolated from others
- **durability**
- once a change has been made, the data is safe, even in the event of system failure
>
> Databases will have mechanisms for **backup**, **distribution**, and **redundancy**, to ensure data is not lost.
> Databases will have mechanisms for **backup**, **distribution**, and **redundancy**, to ensure data is not lost.
## Database management system: DBMS

View file

@ -1,22 +1,22 @@
---
tags:
categories:
- Databases
- Networks
- http
tags: [http]
---
## GET
* Get data
- Get data
## POST
* Create data
- Create data
## PUT
* Update data
- Update data
## DELETE
* Remove data
- Remove data

View file

@ -1,9 +1,7 @@
---
tags:
- Databases
- mongo_db
- node-js
- mongoose
categories:
- Databases
tags: [Databases, mongo_db, node_js, mongoose]
---
# MongoDB connection, set-up and data query: complete example
@ -25,7 +23,7 @@ const courseSchema = new mongoose.Schema({
const Course = mongoose.model("Course", courseSchema);
async function getCourses(){
return await Course
return await Course
.find({isPublished: true, tags: "backend"})
.sort({name: 1})
.select({name: 1, author: 1});

View file

@ -1,9 +1,7 @@
---
tags:
- Databases
- mongo_db
- node-js
- mongoose
categories:
- Databases
tags: [Databases, mongo_db, node_js, mongoose]
---
# Connect to a database with Mongoose
@ -12,11 +10,11 @@ Now that we have installed and configured MongoDB, we need to connect to it via
With Mongoose installed we can connect to a database. We don't have any Mongo databases yet beyond the defaults but the following Mongoose connection logic will create and connect to a new database called `playground`:
Providing the Mongo server is running (execture `mongod`), we will see the confirmation message in the console.
Providing the Mongo server is running (execture `mongod`), we will see the confirmation message in the console.
```js
mongoose
.connect("mongodb://127.0.0.1/playground")
.then(() => console.log("Connected to MongoDB"))
.connect('mongodb://127.0.0.1/playground')
.then(() => console.log('Connected to MongoDB'))
.catch((err) => console.error(err));
```

View file

@ -1,9 +1,7 @@
---
tags:
categories:
- Databases
- mongo_db
- node-js
- mongoose
tags: [mongo_db, node_js, mongoose]
---
# Create collections and documents with Mongoose

View file

@ -1,8 +1,7 @@
---
tags:
- Databases
- mongo_db
- node-js
categories:
- Databases
tags: [mongo_db, node_js, mongoose]
---
# Creating a MongoDB database
@ -15,10 +14,12 @@ $ sudo chown -R `id -un` /data/db
```
Then start the Mongo daemon
```bash
mongod
```
This will run continuously in the terminal and should say somewhere that it is waiting for connections on port `27017`. This command must be executed before you run any backend that interacts with the Mongo database.
This will run continuously in the terminal and should say somewhere that it is waiting for connections on port `27017`. This command must be executed before you run any backend that interacts with the Mongo database.
## MongoDB Compass
@ -27,6 +28,7 @@ _Compass_ is a graphical interface for viewing and interacting with the data in
![](/img/mongo-compass.png)
## Arch Linux troubleshooting
Most times any problems will be a result of a Mongo process that is already running. Resolve with:
```bash
@ -35,6 +37,7 @@ Most times any problems will be a result of a Mongo process that is already runn
sudo lsof -iTCP -sTCP:LISTEN -n -P
sudo kill [pid]
```
Otherwise try the below.
```bash
@ -50,4 +53,4 @@ sudo systemctl start --now mongodb
rm /tmp/mongodb-27017.sock
```
For additional command line utilities you will also need to install `mongodb-tools` from the AUR.
For additional command line utilities you will also need to install `mongodb-tools` from the AUR.

View file

@ -1,21 +1,18 @@
---
tags:
- Databases
- mongo_db
- node-js
- mongoose
categories:
- Databases
tags: [mongo_db, node_js, mongoose]
---
# MongoDB: deleting a document from a collection
```js
async function deleteCourse(id) {
const result = await Course.deleteOne({id: id})
console.log(result)
const result = await Course.deleteOne({id: id});
console.log(result);
}
```
Use `findByIdAndRemove([id])` if you want to return the value that is deleted.
If we were to pass a query object that matches multiple documents in the database to `deleteOne` it would only delete the first document returned. To delete all use `deleteMany`.
If we were to pass a query object that matches multiple documents in the database to `deleteOne` it would only delete the first document returned. To delete all use `deleteMany`.

View file

@ -1,8 +1,7 @@
---
tags:
- Databases
- mongo_db
- node-js
categories:
- Databases
tags: [mongo_db, node_js]
---
# Importing data to MongoDB
@ -13,6 +12,6 @@ We can use the command line to import data into a Mongo database. We can also co
mongoimport --db [preexisting_or_new_database name] --collection [collection_name] --file sourcedata.json --jsonArray
```
We use `--jsonArray` to indicate the format of the data we are importing.
We use `--jsonArray` to indicate the format of the data we are importing.
Once this has executed, the data will be visible in Compass.

View file

@ -1,20 +1,19 @@
---
tags:
- Databases
- mongo_db
categories:
- Databases
tags: [mongo_db]
---
# MongoDB: Introduction
MongoDB is not a relational database system like SQL, instead it is document-based which means you do not neeed to design database tables and schema, you are simply storing data as JSON and there is no transformation of the data.
Most of the notes on Mongo will introduce it within the context of Node.js backend. We will be sending Javascript objects and arrays to Mongo and returning them as JSON.
MongoDB is not a relational database system like SQL, instead it is document-based which means you do not neeed to design database tables and schema, you are simply storing data as JSON and there is no transformation of the data.
Most of the notes on Mongo will introduce it within the context of Node.js backend. We will be sending Javascript objects and arrays to Mongo and returning them as JSON.
## Databases, collections, documents
Although Mongo is not a relational database it has a structure that we can understand in relation to that paradigm. A **database** is obviously the overall structure. It comprises **collections** which are organised sets of data that are analagous to [tables](/Databases/Relational_database_architecture.md#table) in RDBs. Within each collection are a series of **documents** which we can think of as being equivalent to [rows](/Databases/Relational_database_architecture.md) in RDB table: units that comprise the collection.
A document is a container comprising key-value pairs in the manner of an object.
A document is a container comprising key-value pairs in the manner of an object.
![](/img/mongo-db-structure.svg)

View file

@ -1,10 +1,7 @@
---
catagories:
categories:
- Databases
tags:
- mongo_db
- node-js
- mongoose
tags: [mongo_db, node_js, mongoose]
---
# Modelling relationships between data

View file

@ -1,10 +1,7 @@
---
catagories:
categories:
- Databases
tags:
- mongo_db
- node-js
- mongoose
tags: [mongo_db, node_js, mongoose]
---
# Query a Mongo collection with Mongoose

View file

@ -1,53 +1,55 @@
---
tags:
- Databases
- mongo_db
- node-js
- mongoose
categories:
- Databases
tags: [mongo_db, node_js, mongoose]
---
# Update a MongoDB document
There are two methods for updating a document
* query first
* update first
- query first
- update first
## Query first document update
With this approach we first execute a [query](/Databases/MongoDB/Querying_a_collection.md) to retrieve the document we want to edit and then make the change. We use the `findById` method to identify the document by its UUID and then `set` to update specified properties on the document. The `set` method is one of many operators that can be used to update values. For example there is also built-in operators for increment, renaming, multiplying values.
With this approach we first execute a [query](/Databases/MongoDB/Querying_a_collection.md) to retrieve the document we want to edit and then make the change. We use the `findById` method to identify the document by its UUID and then `set` to update specified properties on the document. The `set` method is one of many operators that can be used to update values. For example there is also built-in operators for increment, renaming, multiplying values.
Query first is best used when you want to secure the update with some prior logic or to validate. For example you may not want to update a course if it is listed as published. You could use a query to determine the publish status and then only update the entry if it returns `isPublished: false`.
```js
async function updateCourseFromQuery(id) {
const course = await Course.findById(id);
if (!course) return;
course.set({
isPublished: true,
author: 'A new author'
})
const course = await Course.findById(id);
if (!course) return;
course.set({
isPublished: true,
author: 'A new author',
});
// Instead of an object, we could also set the updated properties individually
course.isPublished = true;
course.author = 'Biggs Volunksire'
const result = course.save()
console.log(result);
// Instead of an object, we could also set the updated properties individually
course.isPublished = true;
course.author = 'Biggs Volunksire';
const result = course.save();
console.log(result);
}
```
## Update first document update
With this approach we don't bother with a prior query. We are confident that the update is legitimate and do not need to first determine that certain conditions are met.
With this approach we don't bother with a prior query. We are confident that the update is legitimate and do not need to first determine that certain conditions are met.
To do this we directly use the `update` method, not `find`:
```js
async function updateCourseFromQuery(id) {
const result = await Course.update({_id: id});
$set: { // Invoke the set operator
author: 'Terry Nutile'
isPublished: true
}
console.log(result)
const result = await Course.update({_id: id});
$set: {
// Invoke the set operator
author: 'Terry Nutile';
isPublished: true;
}
console.log(result);
}
```
@ -56,15 +58,16 @@ This function will just return some metadata about the update. It won't by defau
```js
async function updateCourseFromQuery(id) {
const course = await Course.findByIdAndUpdate(id, {
$set: { // Invoke the set operator
$set: { // Invoke the set operator
author: 'Terry Nutile'
isPublished: true
isPublished: true
}, {new: true}});
console.log(result)
}
```
If we don't add `{new: true}`, it will return the document before the update.
If we don't add `{new: true}`, it will return the document before the update.
### Updating multiple documents at once
// TODO : Add notes on this
// TODO : Add notes on this

View file

@ -1,13 +1,12 @@
---
tags:
- Programming_Languages
categories:
- Databases
- relational_databases
tags: [relational_databases]
---
# Primary key
> Every table in a relational database should have a **primary key**. A primary key is one **field that uniquely identifies each record**.
> Every table in a relational database should have a **primary key**. A primary key is one **field that uniquely identifies each record**.
This is essential for carrying out operations across database tables and for creating and deleting database entires. It is also a safeguard: it means you can always identify a record by itself and don't have to rely on generic queries to identify it.

View file

@ -1,19 +1,18 @@
---
tags:
categories:
- Databases
- REST
- apis
tags: [apis, REST]
---
# RESTful APIs
## Definition of an API
An application programming interface (API) is a set of definitions and protocols for building and integrating application software. It can be thought of as a contract between an information provider and an informational consumer. The API is a mediator between the clients and the resources they wish to acquire from a server or database.
An application programming interface (API) is a set of definitions and protocols for building and integrating application software. It can be thought of as a contract between an information provider and an informational consumer. The API is a mediator between the clients and the resources they wish to acquire from a server or database.
## REST
REST stands for **Representational State Transfer**. It is a set of *architectural constraints* on the structure of an API rather than a fixed protocol. It is a particular way of implementing client-server interaction over HTTP.
REST stands for **Representational State Transfer**. It is a set of _architectural constraints_ on the structure of an API rather than a fixed protocol. It is a particular way of implementing client-server interaction over HTTP.
When a request is made from a client to resources via RESTful API, the API transfers a representation of of the state of the resource to the requester or endpoint. The information is delivered via HTTP. The format can be of several types (HTML, XML, plaintext, Python, PHP etc) but is generally JSON because of its broad compatibility with multiple programming languages.
@ -21,25 +20,25 @@ When a request is made from a client to resources via RESTful API, the API trans
In order to qualify as RESTful, an API must meet the following constraints:
1. **Uniform interface**:
1. **Uniform interface**:
Possess a client-server architecture with request manage through HTTP
1. **Client-server decoupling** :
The client and server applications must be completely independent of one another. The *only* information the client should know about the server is the URI it uses to request the resource, it can't interact with the server in any other way. Likewise, the server shouldn't modify the client application in any way (contrast for example SSR) other than passing the requested data via HTTP.
The client and server applications must be completely independent of one another. The _only_ information the client should know about the server is the URI it uses to request the resource, it can't interact with the server in any other way. Likewise, the server shouldn't modify the client application in any way (contrast for example SSR) other than passing the requested data via HTTP.
1. **Statelessness**
Server applications should not be able to store any data related to a client request. The request alone should contain all the information necessary for processing it, without recourse to any specifics of the client application. For example, a specification of POST with a certain JSON body and header authentication will be all that is provided to the server.
Server applications should not be able to store any data related to a client request. The request alone should contain all the information necessary for processing it, without recourse to any specifics of the client application. For example, a specification of POST with a certain JSON body and header authentication will be all that is provided to the server.
1. **Cacheability**
Where possible, resources should be cacheable on the client or server side. Server responses must contain information about whether caching is allowed for the delivered resource (you see this in the headers in the DevTools console). The goal here is to improve performance on the client side whilst increasing scaleability on the server side.
1. **Layered system architecture**
It may be the case that the data flow between the client and the server is not direct. For instance the request may be funneled through middleware or another program before it is received by the server. Similarly there may be several steps before the client receives the requested data. Whilst one should not assume a direct correspondence, REST APIs need to be designed so that neither the client nor the server can tell whether it communicates with the end application or an intermediary.
Where possible, resources should be cacheable on the client or server side. Server responses must contain information about whether caching is allowed for the delivered resource (you see this in the headers in the DevTools console). The goal here is to improve performance on the client side whilst increasing scaleability on the server side.
1. **Layered system architecture**
It may be the case that the data flow between the client and the server is not direct. For instance the request may be funneled through middleware or another program before it is received by the server. Similarly there may be several steps before the client receives the requested data. Whilst one should not assume a direct correspondence, REST APIs need to be designed so that neither the client nor the server can tell whether it communicates with the end application or an intermediary.
## Example
A basic example of a REST API would be a series of methods corresponding to the main [HTTP request types](/Databases/HTTP_request_types.md).
| HTTP request type | URI | Action | Body ? |
|------------------- |--------------------- |------------------------------ |-------------------------- |
| GET | /api/customers | Retrieve customers as array | No |
| GET | /api/customers/guid | Get a specific customer | No, data comes from GUID |
| PUT | /api/customers/guid | Update an existing customer | Yes |
| DELETE | /api/customers/1 | Delete a customer | No, data comes from GUID |
| POST | /api/customers | Create a new customer | Yes |
| HTTP request type | URI | Action | Body ? |
| ----------------- | ------------------- | --------------------------- | ------------------------ |
| GET | /api/customers | Retrieve customers as array | No |
| GET | /api/customers/guid | Get a specific customer | No, data comes from GUID |
| PUT | /api/customers/guid | Update an existing customer | Yes |
| DELETE | /api/customers/1 | Delete a customer | No, data comes from GUID |
| POST | /api/customers | Create a new customer | Yes |

View file

@ -1,10 +1,11 @@
---
tags:
categories:
- Databases
- relational_databases
tags: [relational_databases]
---
# Relational database architecture
Tables, fields and records are the basic building blocks of databases
![](/img/FL-Databases-1.5_terminology.gif)

View file

@ -1,8 +1,8 @@
---
tags:
- Programming_Languages
categories:
- Databases
- sql
- Programming_Languages
tags: [SQL]
---
# SQL: Demonstration database
@ -11,15 +11,15 @@ For the purposes of demonstration we will work from a made-up database. The exam
This database stores information about computers, their manufacturers, properties and sale data:
* The overall database is `computer_sales`
* It contains the following [tables](/Databases/Relational_database_architecture.md#table): `manufacturer`, `model`, `sales`
* Example [fields](/Databases/Relational_database_architecture.md#field) that belong to these tables: `manufacturer_id` , `model_id` , `name`, `year_founded` , `ram` , `sale_date`
- The overall database is `computer_sales`
- It contains the following [tables](/Databases/Relational_database_architecture.md#table): `manufacturer`, `model`, `sales`
- Example [fields](/Databases/Relational_database_architecture.md#field) that belong to these tables: `manufacturer_id` , `model_id` , `name`, `year_founded` , `ram` , `sale_date`
Below are the `model` and `manufacturer` tables output from the SQLite terminal client.
The model table:
````
```
model_id manufacturer_id name cpu_speed ram cores wifi release_date
---------- --------------- ---------------------- ---------- ---------- ---------- ---------- ------------
1 1 Raspberry Pi 1 Model A 0.7 256.0 1 0 2013-02-01
@ -43,14 +43,14 @@ model_id manufacturer_id name cpu_speed ram cor
19 3 Commodore VIC-20 0.00102 0.005 1 0 1980-01-01
20 3 Commodore 64 0.001023 0.064 1 0 1982-08-01
21 3 Amiga 500 0.00716 0.5 1 0 1987-04-01
````
```
The manufacturer table:
The manufacturer table:
````
```
manufacturer_id name url year_founded trading
--------------- ------------ ----------------------- ------------ ----------
1 Raspberry Pi <https://raspberrypi.org> 2008 1
2 Apple <https://apple.com> 1976 1
3 Commodore <https://www.commodore.c> 1954 0
````
```

View file

@ -1,8 +1,8 @@
---
tags:
- Programming_Languages
categories:
- Databases
- sql
- Programming_Languages
tags: [SQL]
---
# SQL: Joins
@ -13,30 +13,29 @@ Once a relationship has been created using primary and foreign keys (as detailed
We can demonstrate this with the following scenario:
>
> We want to create a list of the name of all computers that have been sold and when they were sold.
> We want to create a list of the name of all computers that have been sold and when they were sold.
This will require us to use the `name` field from the `model` table and the `sale_date` field from the `sales` table.
Here's the SQL:
````sql
```sql
SELECT model.name, sales.sale_date
FROM model
INNER JOIN sales on model.model_id = sales.model_id;
````
```
* We use dot notation to distinguish the `table.field` for each table.
* We use `INNER JOIN` to join the `sales` table with the `model` table where `model_id` field in `model` is the same as the `model_id` field in `sales`
- We use dot notation to distinguish the `table.field` for each table.
- We use `INNER JOIN` to join the `sales` table with the `model` table where `model_id` field in `model` is the same as the `model_id` field in `sales`
This returns:
````sql
name sale_date
-------------------- ----------
```sql
name sale_date
-------------------- ----------
Raspberry Pi 2 Mo 4 2015-02-01
Raspberry Pi 3 Mo 4 2018-11-01
````
```
Note data will only be returned when there is a match between both fields stated in the `SELECT` clause. There must be corresponding data between `model.name` and `sale.sale_data` for a row to be returned. For example if there is a model that has not been sold, there will be a `mode.model_name` but no `sale_data` .
@ -46,12 +45,12 @@ Note data will only be returned when there is a match between both fields stated
In the example above, we used the `INNER JOIN` method. This enshrines the logic:
> return only rows where there is a matching row in both tables
> return only rows where there is a matching row in both tables
Which in the applied context means:
* If there is a model that has never been sold, it wont be returned
* If there is a sale without a model, it wont be returned
- If there is a model that has never been sold, it wont be returned
- If there is a sale without a model, it wont be returned
But there are other types of join that satisfy other types of logic.
@ -62,7 +61,6 @@ The logical state that obtains in the case of **inner joins**:
The logical state that obtains in the case of **left outer joins**
![](/img/2_3.7-Inner_Join_Left.png)
The logical state that obtains in the case of **right outer joins**:
![3_3.7-Inner_Join_Right.png](/img/3_3.7-Inner_Join_Right.png)
@ -71,20 +69,19 @@ The logical state that obtains in the case of **full outer joins**:
![4_3.7-Full_Outer_Join.png](/img/4_3.7-Full_Outer_Join.png)
This type of join is used when you want to discern when there is *not* a match between two fields across tables. For example: imagine that you wanted a list of computers that had never been sold. In this case, you would be interested in rows where there is a `model_id` without a corresponding `sales_id` .
This type of join is used when you want to discern when there is _not_ a match between two fields across tables. For example: imagine that you wanted a list of computers that had never been sold. In this case, you would be interested in rows where there is a `model_id` without a corresponding `sales_id` .
In SQL this would be achieved with:
````sql
```sql
SELECT model.name, sales.sale_date
FROM model
LEFT JOIN sales on model.model_id = sales.model_id;
````
```
Note that this would return all the model names but where there isn't a sale data, `NULL` would be returned. This is an **important distinction :** the outer join method doesn't just return the rows with a `NULL` value for `sale_date` as we might expect. It returns all models along with those that have not been sold. This is because it is oriented to the "left" table, equivalent to the table in the SQL that we cited first with the `on` keyword.
>
> A left outer join returns all the records from the left (model) table and those that match in the right (sales) table. Where there are no matching records in the right (sales) table, a `NULL` value is returned.
> A left outer join returns all the records from the left (model) table and those that match in the right (sales) table. Where there are no matching records in the right (sales) table, a `NULL` value is returned.
A **right outer join**, often referred to as a right join, is the opposite of a left outer; it returns all the records from the right table and those that match in the left table. In our scenario this would be all the models that had a `sale_date` including models that didn't have a `sale_date` , i.e which returned `NULL`
@ -92,9 +89,9 @@ Finally, a **full outer join** returns all the records from both tables, and whe
We can combine multiple types of join in the same SQL query:
````sql
```sql
SELECT model.name, sales.sale_date, manufacturer.url
FROM model
LEFT JOIN sales on model.model_id = sales.model_id
INNER JOIN manufacturer on model.manufacturer_id = manufacturer.manufacturer_id;
````
```

View file

@ -1,37 +1,37 @@
---
tags:
- Programming_Languages
categories:
- Databases
- sql
- Programming_Languages
tags: [SQL]
---
# SQL Aggregate functions
## Count return with custom variable
## Count return with custom variable
````sql
```sql
SELECT COUNT(*) AS total_sales
FROM SALES
````
```
## Sum
````sql
```sql
SELECT SUM(price) as total_value
FROM sales
````
```
## Average
## Average
````sql
```sql
SELECT AVG(price) as average_income
FROM sales
````
```
## Applying aggregate function with sorting applied
````sql
```sql
SELECT COUNT(*) AS total_sales
FROM sales
GROUP BY employee_id
````
```

View file

@ -1,8 +1,8 @@
---
tags:
- Programming_Languages
categories:
- Databases
- sql
- Programming_Languages
tags: [SQL]
---
# SQL: Language structure
@ -11,18 +11,18 @@ Before we start using the syntax we need to understand the grammar:
![](/img/Pasted_image_20220314155028.png)
Expressions differ from clauses and predicates in that they are not the mechanism for returning data (i.e. declaring a clause and a logical colllllndition) they do something to the data, as part of the retrieval. This is a bit subtle:
Expressions differ from clauses and predicates in that they are not the mechanism for returning data (i.e. declaring a clause and a logical colllllndition) they do something to the data, as part of the retrieval. This is a bit subtle:
* `SELECT name FROM model WHERE cores = "4"`
* This retrieves the models that have 4 cores
* `SELECT count(*) FROM model WHERE cores = "4" `
* This counts the number of models that are returned where the counting is a function over and above the retrieval itself.
- `SELECT name FROM model WHERE cores = "4"`
- This retrieves the models that have 4 cores
- `SELECT count(*) FROM model WHERE cores = "4" `
- This counts the number of models that are returned where the counting is a function over and above the retrieval itself.
### Examples from `computer_sales.db`
`sqlite> SELECT * from model WHERE cpu_speed=0.7` : return all models with a CPU speed equal to 0.7:
````
```
model_id manufacturer_id name cpu_speed ram cores wifi release_date
---------- --------------- ---------------------- ---------- ---------- ---------- ---------- ------------
1 1 Raspberry Pi 1 Model A 0.7 256.0 1 0 2013-02-01
@ -30,21 +30,22 @@ model_id manufacturer_id name cpu_speed ram cor
3 1 Raspberry Pi 1 Model B 0.7 512.0 1 0 2012-10-01
4 1 Raspberry Pi 1 Model A 0.7 512.0 1 0 2014-11-01
5 1 Raspberry Pi 1 Model B 0.7 512.0 1 0 2014-07-01
````
```
````
```
count(*)
----------
5
````
> Any value that is not a number should be in single-quotes, never double quotes
```
> Any value that is not a number should be in single-quotes, never double quotes
## Main commands
There are obviously many SQL commands but most standard CRUD actions can be executed with a small number of commands:
* `SELECT`
* `UPDATE`
* `CREATE`
* `INSERT`
* `DELETE`
- `SELECT`
- `UPDATE`
- `CREATE`
- `INSERT`
- `DELETE`

View file

@ -1,47 +1,48 @@
---
tags:
- Programming_Languages
categories:
- Databases
- sql
- Programming_Languages
tags: [SQL]
---
# SQL: The SELECT query
## Print/retrieve/write an entire table, unfiltered
````sql
```sql
SELECT * FROM [table_name]
SELECT * FROM model
````
```
## Retrieve all data from a specific field
````sql
```sql
SELECT [field_name] FROM [table_name]
SELECT name FROM manufacturer
````
```
## Retrieve data and order it
This example orders alphabetically:
This example orders alphabetically:
````sql
```sql
SELECT [field_name] FROM [table_name] ORDER BY [property]
SELECT name FROM model ORDER BY name
````
> When `ORDER BY` is used the default method for strings is alphabetical and for integers it is ascending order.
SELECT name FROM model ORDER BY name
```
> When `ORDER BY` is used the default method for strings is alphabetical and for integers it is ascending order.
Here's a more complex real-life request:
````sql
```sql
SELECT name, cores, ram FROM model ORDER BY ram, name
````
```
It gives us:
````
```
name cores ram
---------------- ---------- ----------
Commodore VIC-20 1 0.005
@ -54,17 +55,17 @@ Raspberry Pi 1 M 1 512.0
Raspberry Pi 1 M 1 512.0
Raspberry Pi 1 M 1 512.0
Raspberry Pi Zer 1 512.0
````
```
But we can obviously specify our own ordering method:
````sql
```sql
SELECT name, cores, release_date FROM model ORDER BY cores DESC, name;
````
```
Returns:
````
```
name cores release_date
----------------- ---------- ------------
Apple MacBook Pro 6 2019-05-21
@ -76,7 +77,6 @@ Raspberry Pi 3 Mo 4 2018-03-14
Raspberry Pi 4 Mo 4 2019-06-24
Raspberry Pi 4 Mo 4 2019-06-24
Raspberry Pi 4 Mo 4 2019-06-24
````
```
>
> `ORDER BY` always comes last, after the selection and any filtering clauses but *before* a `WHERE` clause
> `ORDER BY` always comes last, after the selection and any filtering clauses but _before_ a `WHERE` clause

View file

@ -1,31 +1,29 @@
---
tags:
- Programming_Languages
categories:
- Databases
- sql
- Programming_Languages
tags: [SQL]
---
# SQL: INSERT
## Adding a record
````sql
```sql
INSERT INTO sales
VALUES (1, 11, '2020-01-01','mhogan');
````
```
If you intend to miss out a value, you shouldn't leave it blank, you should instead use `NULL` :
````sql
```sql
INSERT INTO sales
VALUES (1, 11, '2020-01-01', NULL);
````
```
>
> There is a problem with this format: it only works so long as the order to the values in the `VALUES` clause corresponds to the order of the fields in the tables. To rule out error we should instead specify these fields along with the table name:
> There is a problem with this format: it only works so long as the order to the values in the `VALUES` clause corresponds to the order of the fields in the tables. To rule out error we should instead specify these fields along with the table name:
````sql
```sql
INSERT INTO sales**(employee_id, sale_id, model_id, sale_date)**
VALUES ('mhogan', 1, 11, '2020-01-01',);
````
```

View file

@ -1,8 +1,8 @@
---
tags:
- Programming_Languages
categories:
- Databases
- sql
- Programming_Languages
tags: [SQL]
---
# SQL: The WHERE clause and compound statements
@ -11,7 +11,7 @@ Within the `SELECT` statement, the `WHERE` clause specifies the search criterion
`SELECT name, cores, release_date FROM model WHERE CORES="4";`:
````
```
name cores release_date
---------------------- ---------- ------------
Raspberry Pi 2 Model B 4 2015-02-01
@ -22,27 +22,27 @@ Raspberry Pi 4 Model B 4 2019-06-24
Raspberry Pi 4 Model B 4 2019-06-24
Raspberry Pi 4 Model B 4 2019-06-24
Apple iMac 4 2019-03-19
````
```
## Compound statements
Compound statements allow you to apply more filters to your clauses within an SQL statement. SQL allows you to build complex, combinatorial `WHERE` clauses by using Boolean and mathematical operators (i.e `AND` , `OR` , `>` , `<` , `!=` , `<=` ...)
Multiple clauses:
Multiple clauses:
````sql
```sql
SELECT name, ram, release_date
FROM model
WHERE release_date > '2018-01-01' AND ram > 512;
````
```
More complex logic achieve with parentheses:
````sql
```sql
SELECT name, cores, release_date
FROM model
WHERE (manufacturer_id = 1 OR manufacturer_id = 2) AND cores >= 2;
````
```
## Wildcards
@ -50,19 +50,19 @@ SQL does not use Regex. Instead it has a simpler glob-like syntax for carrying o
In order to signal that you wish to compare by a wildcard and not a value, you have to use the `LIKE` keyword. The actual wildcard operator is `%` .
In an SQL statement, the `%` wild card will match any number of occurrences of any character.
In an SQL statement, the `%` wild card will match any number of occurrences of any character.
Any characters can appear before or after MacBook and the record will still be returned:
````sql
```sql
SELECT name, cores, release_date
FROM model
WHERE name LIKE '%MacBook%';
````
```
This wildcard only filters characters that come after `Raspberry` :
````sql
```sql
SELECT name, cores, release_date
FROM model
WHERE name LIKE 'Raspberry%';
````
```

View file

@ -1,8 +1,8 @@
---
tags:
- Programming_Languages
categories:
- Databases
- sql
- Programming_Languages
tags: [SQL]
---
# SQL: The UPDATE query
@ -11,25 +11,25 @@ With UPDATE we modify existing records.
## Schematic syntax
````sql
```sql
UPDATE [table_name]
SET [field]
WHERE [conditional expression/filter]
````
```
## Real example
````sql
```sql
UPDATE manufacturer
SET url = '<http://www.hp.co.uk>'
WHERE manufacturer_id = 4; --typically this will be the primary key as you are updating and existing record and need to identify it uniquely
````
```
## Multiple fields
````sql
```sql
UPDATE manufacturer
SET url = '<http://www.apple.co.uk>',
year_founded = 1977
WHERE manufacturer_id = 2;
````
```

View file

@ -1,12 +1,12 @@
---
tags:
- Programming_Languages
categories:
- Databases
- sql
- Programming_Languages
tags: [SQL]
---
# SQL: The DELETE query
````sql
```sql
DELETE FROM sales WHERE sale_id = 1;
````
```

View file

@ -1,19 +1,18 @@
---
tags:
- Programming_Languages
categories:
- Databases
- sql
- Programming_Languages
tags: [SQL]
---
# SQL: ALTER
We use the `ALTER` query to add, remove and otherwise change the structural properties of a table.
## Add an additional field to existing table
## Add an additional field to existing table
This adds a `price` field to the `sales` table. The `price` field accepts data of the type `real` . `real` is a slightly less precise (less memory) version of float
````sql
```sql
ALTER TABLE sales ADD price real;
````
```

View file

@ -1,15 +1,15 @@
---
tags:
- Programming_Languages
categories:
- Databases
- sql
- Programming_Languages
tags: [SQL]
---
# SQL: CREATE
## Create a table (`CREATE`)
````sql
```sql
CREATE TABLE employee (
employee_id text PRIMARY KEY,
first_name text,
@ -23,6 +23,6 @@ CREATE TABLE employee (
phone_number text,
days_per_week real
);
````
```
We specify the new table name first, then it's fields and their corresponding data types. We also set a primary key
We specify the new table name first, then it's fields and their corresponding data types. We also set a primary key

View file

@ -1,8 +1,8 @@
---
tags:
- Programming_Languages
categories:
- Databases
- sql
- Programming_Languages
tags: [SQL]
---
# SQL: Creating relationships between tables with `PRIMARY` and `FOREIGN` keys
@ -11,16 +11,16 @@ We will demonstrate with an example. We already have the `sales` table. We want
The `sales` table:
````
```
sale_id model_id sale_date employee_id price
---------- ---------- ---------- ----------- ----------
1 44 2020-07-27 tbishop 399.99
2 22 2021-02-07 tbishop 200.99
````
```
Creating the `returns` table and establishing relationship with `sales` using the `FOREIGN KEY` keyword:
Creating the `returns` table and establishing relationship with `sales` using the `FOREIGN KEY` keyword:
````sql
```sql
CREATE TABLE returns (
return_id integer PRIMARY KEY,
sale_id integer NOT NULL,
@ -28,11 +28,11 @@ CREATE TABLE returns (
reason text,
FOREIGN KEY (sale_id) REFERENCES sales(sale_id)
);
````
```
Here's an example with more than one foreign key:
````sql
```sql
CREATE TABLE returns (
return_id integer PRIMARY KEY,
sale_id integer NOT NULL,
@ -42,4 +42,4 @@ CREATE TABLE returns (
FOREIGN KEY(sale_id) REFERENCES sales(sale_id),
FOREIGN KEY(employee_id) REFERENCES employee(employee_id)
);
````
```