SQL count asset inventory - mysql

In sql help i have 3 tables, table one is asset table which is as follow
id
asset_code
asset_name
asset_group
asset_quantity
1
A001
computer
4
7
2
A002
keyboard
6
4
and another table is asset_allocation
id
asset_id
allocated_quantity
allocated_location
returned
1
1
2
IT office
no
2
2
1
main hall
yes
the last table is asset_liquidated which will present assets that are no longer going to be used
id
asset_id
liquidated_quantity
1
1
1
Now lets say that i have 7 computer out of which 2 are allocated but not returned and i have 4 keyboards out of which 1 is allocated and it is returned back and 1 computer is liquidated means it is never going to be used
so now here i want to join these 3 tables and find inventory of my current stock in hand.
Now this is the query now i need to add this
where asset_allocation.returned is enum no inside this query
SELECT id,asset_code, asset_name, asset_group, asset_quantity,allocated_quantity,liquidated_quantity,
asset_quantity - COALESCE(AA.allocated_quantity, 0) - COALESCE(AL.liquidated_quantity, 0) available_quantity
FROM asset A
LEFT JOIN (SELECT asset_id, SUM(allocated_quantity) allocated_quantity
FROM asset_allocation
GROUP BY asset_id) AA ON A.id = AA.asset_id
LEFT JOIN (SELECT asset_id, SUM(liquidated_quantity) liquidated_quantity
FROM asset_liquidated
GROUP BY asset_id) AL ON A.id = AL.asset_id;

I believe what you are looking for is adding WHERE returned = 'no' in your first JOIN like so:
SELECT id,asset_code, asset_name, asset_group, asset_quantity,allocated_quantity,liquidated_quantity,
asset_quantity - COALESCE(AA.allocated_quantity, 0) - COALESCE(AL.liquidated_quantity, 0) available_quantity
FROM asset A
LEFT JOIN (SELECT asset_id, SUM(allocated_quantity) allocated_quantity
FROM asset_allocation
WHERE returned = 'no'
GROUP BY asset_id) AA ON A.id = AA.asset_id
LEFT JOIN (SELECT asset_id, SUM(liquidated_quantity) liquidated_quantity
FROM asset_liquidated
GROUP BY asset_id) AL ON A.id = AL.asset_id;
That changes the available quantity for keyboard from 3 to 4 for me
your query:
vs. mine:

Related

Joining multiple columns into one with union, exclude results with same id

I want to join columns from multiple tables to one column, in my case column 'battery_value' and 'technical_value' into column 'value'. I want to fetch data for only given category_ids, but because of UNION, I get data from other tables as well.
I have 4 tables:
Table: car
car_id model_name
1 e6
Table: battery
battery_category_id car_id battery_value
1 1 125 kW
Table: technical_data
technical_category_id car_id technical_value
1 1 5
3 1 2008
Table: categories
category_id category_name category_type
1 engine power battery
1 seats technical
3 release year technical
From searching, people are suggesting that I use union to join these columns. My query now looks like this:
SELECT CARS.car_id
category_id,
CATEGORIES.category_name,
value,
FROM CARS
left join (SELECT BATTERY.battery_category_id AS category_id,
BATTERY.car_id AS car_id,
BATTERY.value AS value
FROM BATTERY
WHERE `BATTERY`.`battery_category_id` IN (1)
UNION
SELECT TECHNICAL_DATA.technical_category_id AS category_id,
TECHNICAL_DATA.car_id AS car_id,
TECHNICAL_DATA.value AS value
FROM TECHNICAL_DATA
WHERE `TECHNICAL_DATA`.`technical_category_id` IN (3))
tt
ON CARS.car_id = tt.car_id
left join CATEGORIES
ON category_id = CATEGORIES.id
So the result I want is this, because I only want to get the data where category_id 1 is in battery table:
car_id category_id category_name technical_value
1 1 engine power 125 kW
1 3 release year 2008
but with the query above I get this, category_id 1 from technical table is included which is not something I want:
car_id category_id category_name value
1 1 engine power 125 kW
1 1 seats 125 kW
1 3 release year 2008
How can get exclude the 'seats' row?
For the results you want, I don't see why the cars table is needed. Then, you seem to need an additional key for the join to categories based on which table it is referring to.
So, I suggest:
SELECT tt.*, c.category_name
FROM ((SELECT b.battery_category_id AS category_id,
b.car_id AS car_id, b.value AS value,
'battery' as which
FROM BATTERY b
WHERE b.battery_category_id IN (1)
) UNION ALL
(SELECT td.technical_category_id AS category_id,
td.car_id AS car_id, td.value AS value,
'technical' as which
FROM TECHNICAL_DATA td
WHERE td.technical_category_id IN (3)
)
) tt LEFT JOIN
CATEGORIES c
ON c.id = tt.category_id AND
c.category_type = tt.which;
That said, you seem to have a problem with your data model, if the join to categories requires "hidden" data such as the type. However, that is outside the scope of the question.

Two tables with all rows including allocated based on id

Im trying to make this generic as it might help others in the future.
For an example i have two tables one with books and the other is the user with which book they have read, So ide like to display all the books and include a temporary column value as a (yes / no or 0/1), i have tried a join but the ( WHERE user_id = 3) clause only then return the one row and not all the other rows.
book.book_id book.book_name
10 Book 1
11 Book 2
12 Book 3
-------------
user.user_id user.book_id
1 10
1 12
2 11
3 12
Desired output:
user_id book_id temp_col_read
3 10 0 // yes, on or null
3 12 1 // or yes
3 13 0
This is actually quite simple. In the event that a user could read a book multiple times, I would go with exists in the select:
select b.*,
(case when exists (select 1
from reads r
where r.book_id = b.book_id and r.user_id = 3
)
then 1 else 0
end) as user_read_book
from book b;
In MySQL, the case is not strictly necessary because a boolean expression is treated as 0/1 in many contexts:
select b.*,
(exists (select 1
from reads r
where r.book_id = b.book_id and r.user_id = 3
) as user_read_book
from book b;
You can use a left join and where the join is unresolved then is not read
select
user.user_id
, book.book_id
, case
when book.book_id is null
then 'NO' else 'YES'
end as temp_col_read
from book
left join user on user.book_id = book.book_id

Complex SQL Union

Any SQL Guru's out there I could use some help! I am creating a stored procedure that I believe needs a Union so that all the results are brought back with 1 SELECT statement.
I have simplified my problem to the tables below:
user
user_id username name DOB
------------------------------------------------------
1 JohnSmith1 John Smith 01/01/1990
2 LisaGreen17 Lisa Green 03/07/1986
3 BarneyB Barney Brown 09/12/1960
user_team
user_team_id user_id team_id total_score
-------------------------------------------------------------
1 1 1 29
2 2 7 37
3 3 2 15
private_league
priv_league_id league_name host_user league_password
-------------------------------------------------------------------------
1 Lisa's League 2 CSUASH429d9
2 Barney's Bonanza 3 Jkap89f5I01
user_team_private_league_M2M
id priv_league_id user_team_id
----------------------------------------
1 1 1
2 1 2
3 1 3
4 2 1
5 2 3
I would like to run a stored procedure with an input of a user_id which will bring back all leagues entered by the user, the host of each of those leagues, how many total players have entered in each league and what position the user is in for each of those leagues(sorted by total score).
At the moment I have:
CREATE DEFINER=`root`#`localhost` PROCEDURE `user_private_leagues`(IN v_user_id INT)
BEGIN
DECLARE userteamid INT;
# Retrieve user team from a user_id
SELECT user_team_id INTO userteamid
FROM user_team
WHERE user_id = v_user_id;
# Retrieve private league name and host user (for a userteam)
SELECT private_league.league_name, private_league.host_user
FROM user_team_private_league_M2M
INNER JOIN privateleague
ON user_team_private_league_M2M.priv_league_id=private_league.priv_league_id
WHERE user_team_id = userteamid;
END
This query does not include the total number of players for each league and the current position of the user
I have created a query to bring back the total users for each private league, with no user filter like so:
SELECT private_league_id, COUNT(*) AS total_users
FROM classicseasonmodel_classicseasonuserteamprivateleague
GROUP BY private_league_id;
A query for the user's current position can be worked out by using the answer to this question and using total_score.
I am extremely stuck with this at the moment - the perfect result from the SP will be as follows:
CALL user_private_leagues(3); (user id of BarneyB)
priv_league_name current_position total_users host_user
-----------------------------------------------------------------------
Lisa's League 3 3 LisaGreen17
Barney's Bonanza 2 2 BarneyB
Thanks!
Sorry but I didn't create the DB to test the SQL below. But you can start from there. No need for UNION. I didn't understand the business rule to compute the user's position in the league, since it may come from the team or the user.
select priv_league_id, league_name, host_user_name, count(*) as total_users
from (
select A.priv_league_id, A.league_name, D.name as host_user_name, B.user_team_id, C.user_id, D.
from private_league A
join user_team_private_league_M2M B
on A.priv_league_id = B. priv_league_id
join user_team C
on B.user_team_id = C. user_team_id
join user D
on A.host_user = D.user_id
) D
group by priv_league_id
Let take it step by step....
First ID, Count for pleague
SELECT private_league_id, COUNT(*) AS total_users
FROM classicseasonmodel_classicseasonuserteamprivateleague
GROUP BY private_league_id;
Now add in Name and host user
SELECT PL.league_name, LC.uCNT, PL.host_user
FROM (SELECT private_league_id AS pID, COUNT(*) AS uCNT
FROM classicseasonmodel_classicseasonuserteamprivateleague
GROUP BY private_league_id ) AS LC
LEFT JOIN private_league PL ON PL.priv_league_id = LC.pID
Now add in host user name
SELECT PL.league_name, LC.uCNT as total_users, hu.name as host_user
FROM (SELECT private_league_id AS pID, COUNT(*) AS uCNT
FROM classicseasonmodel_classicseasonuserteamprivateleague
GROUP BY private_league_id ) AS LC
LEFT JOIN private_league PL ON PL.priv_league_id = LC.pID
LEFT JOIN user hu ON PL.host_user = hu.user_id
Don't know where current position is.
This query will give users and position for each team, join to this and limit by user id to get one users position for each team:
select UT.user_id,
UT.team_id,
ROW_NUMBER() OVER (PARTITION BY team_id ORDER BY total_score DESC) AS team_position
from private_league L
join user_team_private_league_M2M LJ ON L.priv_league_id = LJ.priv_league_id
join user_team UT ON LJ.user_team_id = UT.user_team_id

How to get 2 results from 3 tables with 1 mysql syntax

I have 3 tables like this
soft_id soft_name
1 Office
pu_id soft_id pu_quantity
1 1 10
2 1 20
3 1 30
own_id soft_id owner
1 1 Peter
2 1 Tommy
3 1 David
How can I have a result like this in one single mysql query
soft_id soft_name sum(pu_quantity) count(owner)
1 Office 60 3
Try this:
SELECT a.soft_id,
a.soft_name,
b.p_cnt AS quantity,
c.o_cnt AS owner_count
FROM soft a
INNER JOIN
(SELECT soft_id, SUM(pu_quantity) AS p_cnt FROM product GROUP BY soft_id
) b
ON a.soft_id = b.soft_id
INNER JOIN
(SELECT soft_id, COUNT(*) AS o_cnt FROM owner GROUP BY soft_id
) c
ON b.soft_id = c.soft_id
GROUP BY a.soft_id,
a.soft_name
SQLFiddle
Note: assuming that the table names are soft, product and owner respectively.
Try this
SELECT S.soft_id,S.soft_name,P.sum(pu_quantity),O.count(owner)
FROM Soft S INNER JOIN Product P ON S.soft_id = P.soft_id
Inner JOIN Owner O = P.soft_id = O.soft_id
Group By S.soft_id,P.soft_id,O.soft_id,S.soft_name

mysql select matching results

I'm trying to find the leagues (lid) where two users are apart of.
Here are my tables:
Table leagues:
*id* lname
--------------
1 Hard C
3 Fun
5 Crazy
Table match:
*userid* *lid*
-----------------
1 1
4 5
1 3
2 1
4 1
4 3
*Are primary keys
match.lid is foreign key to leagues.id (a user cannot not be part of the same league twice)
Here's what I have so far (a start):
SELECT t1.lid, t2.lname
FROM match t1
JOIN leagues t2 on t1.lid = t2.id
So far I managed to join the two tables and get the names. My ultimate goal is to show the lid's where two users are part of the same league, say userid 1 and 4.
userid 1 is a member of lid 1 and 3
userid 4 is a member of lid 5, 1, and 3
Both users meet in league(lid) 1 and 3
So I need a query that shows only the league where both users meet. Like this:
lid lname
--------------
1 Hard C
3 Fun
Since userid 1 and 4 meet in league 1 and 3, the results should show that. I can run two queries for each user and check which leagues both users meet via php, but I think it's more efficient to run one query.
SELECT m1.lid, l.lname FROM
`match` m1, `match` m2, leagues l
WHERE m1.lid = m2.lid AND m1.lid = l.id
AND m1.userid = 1
AND m2.userid = 4
There are a few ways. The most straightforward is:
SELECT id AS lid,
lname
FROM leagues
WHERE id IN
( SELECT lid
FROM match
WHERE userid = 1
)
AND id IN
( SELECT lid
FROM match
WHERE userid = 4
)
;
Another way, which is a bit less direct, but may perform better — you can try it and see — is to use JOIN:
SELECT id AS lid,
lname
FROM leagues
JOIN match AS match1
ON match1.lid = leagues.id
AND match1.userid = 1
JOIN match AS match2
ON match2.lid = leagues.id
AND match2.userid = 4
;