SQLite: Loop over SELECT statement, replacing the WHERE clause - sqlite

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;

Related

get count of all related column on relationship

in sqlite i have this tables:
CREATE TABLE sessions(
id INTEGER PRIMARY KEY AUTOINCREMENT,
session_name TEXT,
session_comment TEXT,
session_type INTEGER,
date_time TEXT)
CREATE TABLE barcodes(
id INTEGER PRIMARY KEY AUTOINCREMENT,
barcode TEXT,
session_id INTEGER,
enter INTEGER,
exit INTEGER,
date_time TEXT)
sessions is main table and i store some data in other table as barcodes with specifying session_id in barcodes table, now i want to get all column data from sessions with count of all barcodes table witch session_id in that equals with sessions.id
for example:
select *, count(barcodes) as cnt from sessions
left join barcodes on sessions.id = barcodes.session_id
try below query
SELECT *, COUNT(b.barcodes) as cnt FROM
sessions s
LEFT JOIN barcodes b ON s.id = b.session_id
GROUP BY b.id

SQL query to relate 2 tables

I want to relate following 2 tables in sqlite3. What I understood from other examples is that we should have some common field between each table, so I added order_ID.
1) How to write sqlite queries for creating the relation between these tables?
2) How to manage Table 2, where same order can have multiple products, so order ID is repeated. An order can have min 1 and max 10 products. So it has dynamic range of 1-10.
table 1:
order_ID date buyer ship_chr
001 01/01 abc 15
002 05/01 xyz 10
table 2:
order_ID prod quantity rate
001 pen 50 2
001 paper 25 1
001 pin 50 2
002 paper 25 1
002 pen 100 2
It looks like you want to store orders and information about those orders. First, make an orders table.
create table orders (
id integer primary key autoincrement,
created_at timestamp not null default current_timestamp,
buyer text not null,
ship_chr text not null
)
Note that instead of order_id, the primary key of a table is just id.
It's not required, but it is a convention I like as it keeps primary and foreign keys distinct.
Also note that I'm using the timestamp type to store dates, this will make working with those dates much easier as you can use SQLite date functions.
Now we need a table for information about what is in each order.
create table order_products (
id integer primary key autoincrement,
order_id integer not null references orders(id),
product text not null,
quantity integer not null,
rate integer not null
)
This sets up a one-to-many relationship betweeen orders and order_products.
One order can have many products. You can link these tables together using
a join. Here's how you'd get
the buyer for each product.
select o.buyer, op.product, op.quantity
from order_products op
join orders o on o.id = op.order_id
abc|pen|50
abc|paper|25
abc|pin|50
xyz|paper|25
xyz|pen|100
join orders o on o.id = op.order_id says for every row in order_products find one in orders where order.id matches the row's order_id and treat them both as a single row.
From here you'll probably want to make products and buyer their own tables
as well to store any information about the buyers and products. It also ensures
that the products and buyers exist avoiding typos.
create table buyers (
id integer primary key autoincrement,
name text not null,
address text not null,
phone text not null
);
create table products (
id integer primary key autoincrement,
name text not null,
stock integer not null default 0
);
create table orders (
id integer primary key autoincrement,
created_at timestamp not null default current_timestamp,
buyer_id integer references buyers(id) not null,
ship_chr text not null
);
create table order_products (
id integer primary key autoincrement,
order_id integer not null references orders(id),
product_id integer not null references products(id),
quantity integer not null,
rate integer not null
);
Then you can join everything together to get information about products and buyers.
select b.name, p.name, op.quantity
from order_products op
join orders o on o.id = op.order_id
join buyers b on b.id = o.buyer_id
join products p on p.id = op.product_id
name|name|quantity
abc|pen|50
abc|paper|25
abc|pin|50
xyz|paper|25
xyz|pen|100
SQL Fiddle
If you don't do this now it will be harder to do later.

Sqlite - combining 2 SELECT statements from same table

I need to combine 2 results from SELECT statements that look in the same table.
What I have works but I'm sure there is a better way to do it.
SELECT
games._id,win.winner,deal.dealer
FROM
games,
(SELECT
players.name as winner
FROM
games, players
WHERE
players._id = games.winner
AND games._id = 2) AS win,
(SELECT
players.name as dealer
FROM
games, players
WHERE
players._id = games.dealer
AND games._id = 2) AS deal
WHERE
games._id = 2
Thanks for your help optimizing this query.
EDIT:
The schema for the tables are:
CREATE TABLE games
(
_id INTEGER PRIMARY KEY,
winner integer,
dealer integer
)
CREATE TABLE players
(
_id INTEGER PRIMARY KEY,
name text
)
Something like below(untested code) should work:
SELECT g._id,p1.name AS winner,p2.name AS dealer
FROM games AS g join players AS p1 ON p1._id = g.winner
JOIN players AS p2 on p2._id = g.dealer
WHERE g._id = 2

Join two tables in SQLite and Count

I have two tables named "likes" and "comments" and I want to have a table which has counts of likes and comments for each specific user, I wrote following query in SQLite but result is not true for all users, count values for users in both tables are multiple of number of likes and number of comments.
SELECT
likes.liker_name, likes.liker_id, likes.profile_picture ,
COUNT(comments.commenter_name) AS comment_count, COUNT( likes.liker_id) AS like_count
FROM likes
LEFT JOIN comments
ON likes.liker_name = comments.commenter_name
GROUP BY
likes.liker_name
ORDER BY
COUNT( likes.liker_id) DESC
How can I get correct value of count for users that exist in both tables?
The problem is: Some users have comments but no likes, others have likes but no comments, some have both and some have none. Therefore I suggest using a union query and summing that one again
SELECT
u.name, u.id, u.profile_picture,
SUM(u.like_count) AS like_count, SUM(u.comment_count) AS comment_count
FROM (
SELECT
liker_name AS name, liker_id AS id, profile_picture,
COUNT(*) AS like_count, 0 AS comment_count
FROM
likes
GROUP BY
liker_name, liker_id, profile_picture
UNION ALL
SELECT
commenter_name AS name, commenter_id AS id, profile_picture,
0 AS like_count, COUNT(*) AS comment_count
FROM
comments
GROUP BY
commenter_name, commenter_id, profile_picture
) AS u
GROUP BY
u.name, u.id, u.profile_picture
If you have a separate user table you could also left join the likes count and the comments count subqueries to the user table
SELECT
u.name, u.id, u.profile_picture, l.cnt AS like_count, c.cnt AS comment_count
FROM
users u
LEFT JOIN
(SELECT liker_id, COUNT(*) AS cnt
FROM likes
GROUP BY liker_id
) AS l
ON u.user_id = l.liker_id
LEFT JOIN
(SELECT commenter_id, COUNT(*) AS cnt
FROM comments
GROUP BY commenter_id
) AS c
ON u.user_id = c.commenter_id
WHERE l.cnt > 0 OR c.cnt > 0
No matter how you make it, you must count the comments and the likes in separate subqueries. If you count after joining you are summing on a result where records might be duplicated (the ones on the left side) and you are getting the wrong count.

trigger insert different row

The sqlite3 trigger that I want to create might or might not be possible with sql. Five tables are involved:
Members Groups GroupMembers Accounts
mId |name| accId gId | name | accId gId | mId accId | balance
Orders
oId | accId | ammount
When someone deletes a group, I want to make an order for each of the group members with the average of the group balance. So it should do something like this:
CREATE NEW TRIGGER triggername
BEFORE DELETE ON Groups
WHEN ((SELECT balance FROM Accounts WHERE accId=OLD.accId) = 0)
FOR EACH ROW IN
(SELECT accId
FROM GroupMembers JOIN Members ON GroupMembers.mId = Members.mId
WHERE GroupMembers.gId = OLD.gId)
BEGIN
INSERT INTO Orders(accId,ammount) VALUES(accId,
(SELECT balance FROM Accounts WHERE accId = OLD.accId)
/
(SELECT SUM(mId) FROM GroupMembers WHERE gId = OLD.gId)
);
END
The question is: is it possible to create a FOR EACH ROW in any other table than the table at which the trigger applies? Is it possible to put the WHEN statement before the FOR EACH statement?
As documented, there is no such a thing as a FOR EACH ROW IN ... clause.
However, the INSERT statement can use a SELECT statement as the source of the data to be inserted.
Write a SELECT statement that returns one row for each group member:
CREATE TRIGGER triggername
AFTER DELETE ON Groups
FOR EACH ROW
BEGIN
INSERT INTO Orders(accId, amount)
SELECT accId,
(SELECT balance
FROM Accounts
WHERE accId = OLD.accId) /
(SELECT COUNT(*)
FROM GroupMembers
WHERE gId = OLD.gId)
FROM Members
WHERE mId IN (SELECT mId
FROM GroupMembers
WHERE gId = OLD.gId);
END;
(I dropped the balance = 0 filter.)

Resources