How to subtract two rows from two different selects? - sqlite

I'm trying to subtract the total number shares for each symbol from the sell orders and the buy orders so I can have that total of shares owned.
buy = db.execute("SELECT symbol,SUM(shares) as total FROM negocios WHERE userid = ? and operation = 'buy' GROUP BY symbol");
sell = db.execute("SELECT symbol,SUM(shares) as total FROM negocios WHERE userid = ? and operation = 'sell' GROUP BY symbol")
I want a table like this with the values already subtracted:
symbol
total
CSCO
25
GOOG
6
NFLX
32
I was trying :
SELECT ((SELECT symbol,SUM(shares) as total FROM negocios WHERE userid = ? and operation = 'buy' GROUP BY symbol) - (SELECT symbol,SUM(shares) as total FROM negocios WHERE userid = ? and operation = 'sell' GROUP BY symbol) AS diff;
But I'm getting an error:
Parse error: sub-select returns 2 columns - expected 1
Table schema:
CREATE TABLE negocios (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, userid TEXT NOT NULL, symbol TEXT NOT NULL, operation TEXT CHECK( operation IN ('buy', 'sell')), price DECIMAL(10,2), time TIMESTAMP, shares DECIMAL(10,2), name TEXT);

You can do it with a single query if you use conditional aggregation:
userid = 100 #variable that stores the user's id
sql = """
SELECT symbol,
SUM(shares * CASE operation WHEN 'buy' THEN 1 WHEN 'sell' THEN -1 END) AS total
FROM negocios
WHERE userid = ?
GROUP BY symbol
"""
result = db.execute(sql, (userid,))

Related

Hello how can i joint table in progress 4gl? And display

Define variable i as integer no-undo.
For each Sports.customer where Sports.customer.CustNum = 1 AND Sports.Order.OrderDate = 11/21/1997 NO-LOCK.
/* it says Missing for find etc */
I need to display the Order of Lift Tours i used his primary key but im having trouble to access the 2 tables
Tables
Customer PK CustNum
Order PK OrderName FK CustNum
Order-line PK Orderline
I need to display the Orders of Lift Tours with the date order of 11/21/1997 and diplay total price of lift tours
Thanks guys
define variable orderTotal as decimal no-undo.
for each customer no-lock where name = "Lift Tours",
each order no-lock where order.custNum = customer.custNum and order.orderDate = 11/21/1997,
each orderLine no-lock where orderLine.orderNum = order.orderNum:
orderTotal = orderTotal + ( orderLine.Qty * orderLine.price ).
end.
display orderTotal.
The "," is used to join WHERE clauses in the FOR EACH. You specify the common fields to make the join on in those WHERE clauses.
For total price, you'll have to join Order and OrderLine.
DEFINE VARIABLE deTotal AS DECIMAL NO-UNDO.
FOR EACH Order WHERE Order.CustNum = 1 AND Order.OrderDate = 11/21/1997 NO-LOCK,
EACH OrderLine OF Order NO-LOCK:
ASSIGN deTotal = deTotal = deTotal + OrderLine.Qty * OrderLine.Price .
END.

substring: row information to field names

I have information in an SQLite database. The database structure can not be changed.
I am trying to construct a query that will give me a result in which the TypeOfInformation entries are field names:
My first try was to work with subqueries:
SELECT (SELECT Value FROM FinData WHERE Type = 'Price') AS Price,
(SELECT Value FROM FinData WHERE Type = 'Volume') AS Volume
FROM FinData")
Seemed perfect, however, the result was a resultset in which EVERY entry in the columns Price and Volume are equal to the FIRST respective entry of Price and Volume in the original database:
I tried to get around this and to include the other Price and Volume information ­- but I failed. (Which is a pity, because the syntax seemed somehow easy to grasp.)
Next try was the following:
Select Date, Value AS Volume From FinData WHERE Volume IN
(SELECT Value FROM FinData WHERE (Type = 'Volume'))
This gives me a resultset with a Volume column and all volume information. Okay, so far. However, when I want to complement this resultset which a Price column via
Select Date, Value AS Volume From FinData WHERE Volume IN
(SELECT Value FROM FinData WHERE (Type = 'Volume'))
union
Select Date, Value AS Close From FinData WHERE Price IN
(SELECT Value FROM FinData WHERE (Type = 'Price'))
I get a resultset that shows Price and Volume information in only ONE column ("Volume"), which therefore is also useless.
To look up a value corresponding to a row in the outer query, you have to use a correlated subquery, which explicitly makes a connection between both:
SELECT Date,
(SELECT Value
FROM FinData
WHERE Date = Dates.Date
AND TypeOfInformation = 'Price'
) AS Price,
(SELECT Value
FROM FinData
WHERE Date = Dates.Date
AND TypeOfInformation = 'Volume'
) AS Volume
FROM (SELECT DISTINCT Date
FROM FinData) AS Dates;
(The DISTINCT subquery is used to prevent multiple rows for each date.)
Alternatively, group all rows for a date, and use aggregation functions and CASE expressions to extract the values from the proper rows:
SELECT Date,
MAX(CASE WHEN TypeOfInformation = 'Price' THEN Value END) AS Price,
MAX(CASE WHEN TypeOfInformation = 'Volume' THEN Value END) AS Volume
FROM FinData
GROUP BY Date;
Assuming dates are unique per price volume pair, you can do this:
with xxx(date,price,volume) as
(
select date,value,0 from findata where typeofinformation = 'Price'
union
select date,0,value from findata where typeofinformation = 'Volume'
)
select date,sum(price) price,sum(volume) volume from xxx group by date;

How to increment quantity column if record exists, else insert record?

I've got the below sqlite database:
CREATE TABLE `test` (
`idx` INTEGER PRIMARY KEY AUTOINCREMENT,
`qty` INTEGER,
`brand` TEXT,
`type` TEXT
);
insert into test (qty, brand, type) values (1, "Merc", "petrol");
insert into test (qty, brand, type) values (1, "Toyota", "diesel");
I want to insert another record but if it exists then I want to increase the qty field, so:
insert into test (qty, brand, type) values (1, "Merc", "diesel");
so would just increase the qty field by one, and
insert into test (qty, brand, type) values (1, "Merc", "petrol");
would insert a new record.
SQLite is an embedded database, i.e., it is designed to be used together with an application.
The easiest way is to put the logic into the application:
db.execute("UPDATE test SET qty = qty + 1 WHERE brand = ? AND type = ?",
["Merc", "diesel"])
if db.rows_affected == 0:
db.execute("INSERT ...")
As of version 3.24.0, SQLite supports UPSERT.
CREATE TABLE `test` (
`idx` INTEGER PRIMARY KEY AUTOINCREMENT,
`qty` INTEGER DEFAULT 1,
`brand` TEXT,
`type` TEXT
)
UNIQUE (brand, type)
;
INSERT INTO test (qty, brand, type) VALUES ("Merc", "diesel")
ON CONFLICT(brand, type) DO UPDATE SET qty = qty + 1;
INSERT INTO test (qty, brand, type) VALUES ("Merc", "diesel")
ON CONFLICT(brand, type) DO UPDATE SET qty = qty + 1;
SELECT qty, brand, type FROM test;
Output:
2 Merc diesel

SQLite: Loop over SELECT statement, replacing the WHERE clause

I have following two tables:
CREATE TABLE messages (
id integer UNIQUE NOT NULL,
message text,
recipient integer NOT NULL,
sender integer NOT NULL,
sent_at text NOT NULL,
FOREIGN KEY (recipient) REFERENCES users (id),
FOREIGN KEY (sender) REFERENCES users (id)
);
CREATE TABLE users (
id integer UNIQUE NOT NULL,
username text NOT NULL,
);
I need a very specific query, that looks like the following:
SELECT *
FROM messages
WHERE sender = 123 OR recipient = 123
ORDER BY id desc
LIMIT 1
I need to kind of iterate over the messages table, using every user, and putting him in the WHERE statement.
-- TABLE 'users':
-- 123 = id of user1
-- 456 = id of user2
-- 789 = id of user3
Is it possible to iterate in SQLite?
Goal is, to get the newest "conversation" for every user in the users table. For every user, the newest message involving him should be displayed, no matter if that newest message was sent or recieved by him.
You could use a correlated subquery to get that value for each user ID:
SELECT id,
username,
(SELECT MAX(id)
FROM messages
WHERE sender = users.id
OR recipient = users.id
) AS last_message_id
FROM users
This is also possible with GROUP BY.
First join the two table together, then create a group for each user:
SELECT users.id,
MAX(messages.id)
FROM users
JOIN messages ON users.id = messages.sender OR
users.id = messages.recipient
GROUP BY users.id
SELECT year , COUNT(*) AS Count
FROM Movie
WHERE Movie.MID NOT IN
(SELECT DISTINCT m.MID
FROM Movie m
JOIN M_Cast m_c ON m.MID = m_c.MID
JOIN Person p_1 ON m_c.PID = p_1.PID
AND p_1.Gender='Male')
AND Movie.MID IN
(SELECT DISTINCT m.MID
FROM Movie m
JOIN M_Cast m_c ON m.MID = m_c.MID
JOIN Person p_1 ON m_c.PID = p_1.PID
AND p_1.Gender='Female')
GROUP BY year;

Time Difference between query result rows in SQLite: How To?

Consider the following reviews table contents:
CustomerName ReviewDT
Doe,John 2011-06-20 10:13:24
Doe,John 2011-06-20 10:54:45
Doe,John 2011-06-20 11:36:34
Doe,Janie 2011-06-20 05:15:12
The results are ordered by ReviewDT and grouped by CustomerName, such as:
SELECT
CustomerName,
ReviewDT
FROM
Reviews
WHERE
CustomerName NOT NULL
ORDER BY CustomerName ASC, ReviewDT ASC;
I'd like to create a column of the time difference between each row of this query for each Customer... rowid gives the original row, and there is no pattern to the inclusion from the rowid etc...
For the 1st entry for a CustomerName, the value would be 0. I am asking here incase this is something that can be calculated as part of the original query somehow. If not, I was planning to do this by a series of queries - initially creating a new TABLE selecting the results of the query above - then ALTERING to add the new column and using UPDATE/strftime to get the time differences by using rowid-1 (somehow)...
To compute the seconds elapsed from one ReviewDT row to the next:
SELECT q.CustomerName, q.ReviewDT,
strftime('%s',q.ReviewDT)
- strftime('%s',coalesce((select r.ReviewDT from Reviews as r
where r.CustomerName = q.CustomerName
and r.ReviewDT < q.ReviewDT
order by r.ReviewDT DESC limit 1),
q.ReviewDT))
FROM Reviews as q WHERE q.CustomerName NOT NULL
ORDER BY q.CustomerName ASC, q.ReviewDT ASC;
To get the DT of each ReviewDT and its preceding CustomerName row:
SELECT q.CustomerName, q.ReviewDT,
coalesce((select r.ReviewDT from Reviews as r
where r.CustomerName = q.CustomerName
and r.ReviewDT < q.ReviewDT
order by r.ReviewDT DESC limit 1),
q.ReviewDT)
FROM Reviews as q WHERE q.CustomerName NOT NULL
ORDER BY q.CustomerName ASC, q.ReviewDT ASC;

Resources