Query for showing stock as of given date in the past - mysql

I am developing software for warehouse management.
I got three tables: itemstock, documents, doc_pcs
itemstock fields (not all of them are shown):
rfid_no (which is unique and primary key)
item_name
status
documents fields:
id
doc_date
doc_type
doc_pcs fields:
id
id_doc | these two are primary key
pos | (id_doc is connected to documents.id)
rfid_no (from itemstock.rfid_no)
First table is for collecting records of items, nothing is ever erased from this table, there's just status change when something happens with particular item (goes out to client, comes back etc).
Documents and doc_pcs tables store document data.
doc_type is for marking whether items on document were going in or out of the warehouse.
The problem is:
I need to create query that shows all the stock as of given date.
In other words:
It should show all items from today's itemstock with status=6 ("stored") MINUS records with rfid_no that have matches in doc_pcs related to documents dated between today and a given date and with doc_type="out" PLUS records with rfid_no that have matches in doc_pcs related to documents dated between today and a given date and with doc_type="in"
Was searching for any clue here and there for few days now and I could not find anything that will lead me to any solution. I will be gratefull for any help!
Sample data:
itemstock (as of today):
00300D0909DA, "tshirt", 6
00300D0909DB, "apron", 6
00300D0909DC, "tshirt", 6
00300D0909DD, "trousers", 6
00300D0909DE, "tshirt", 1
00300D0909DF, "trousers", 1
00300D0909E0, "trousers", 6
documents:
0,2015-08-01,"in"
1,2015-08-02,"in"
2,2015-08-03,"out"
3,2015-08-04,"in"
4,2015-08-05,"out"
5,2015-08-06,"in"
doc_pcs:
0, 1, 00300D0909DA
0, 2, 00300D0909DE
1, 1, 00300D0909DF
1, 2, 00300D0909DD
2, 1, 00300D0909DE
3, 1, 00300D0909DB
4, 1, 00300D0909DF
5, 1, 00300D0909DC
5, 2, 00300D0909E0
query results for given doc_date=2015-08-04 including fields rfid_no and item_name should be:
00300D0909DA, "tshirt"
00300D0909DB, "apron"
00300D0909DD, "trousers"
00300D0909DF, "trousers"
EDIT:
I've managed to make following query but it executes endlessly hence I believe something is wrong:
SELECT DISTINCT c.rfid_no
FROM itemstock c LEFT JOIN doc_pcs d
ON c.rfid_no=d.rfid_no
WHERE c.status=6
OR
(d.id IN
(SELECT dk.id
FROM documents dk
WHERE DATE(dk.doc_date)>='2015-08-04'
AND dk.doc_type="out")
AND
d.id NOT IN
(SELECT dk.id
FROM documents dk
WHERE DATE(dk.doc_date)>='2015-08-04'
AND dk.doc_type="in"))

It seems like you could either go from today's values and work backwards or you could start from 'day 0' and work forwards. By storing the stock count as of 'today' you are denormalizing the data so I'd opt for the second approach (and maybe you could save yourself a table).
Assume that as of 'day 0' all stock is empty. To get the stock count as of a given date you would (p-query):
select sum((select count inbound where date <= inventory_date) - (select count outbound where date <= inventory_date))

Related

Need to retrieve the most recent room type/Rateplan combination (mysql)

I will explain the logic:
I need to retrieve only the most recent room type/rate plan combinations from the rateplan_roomtypeTable.
room type ID and rate plan id are located in separate columns
there are 2 conditions that need to be met: all active room type/rate plan combinations need to be retrieved along with all room type/rate plan combinations that have produced even if they are not active. All these combinations need to be the most recent ones.
The desired results would be like the table I ll share with you:
Your help with the below query will be much appreciated:
select
Id
, RoomTypeId
, RateTypeId
,isactiveRateType
,isactiveRoomType
, RatePlanName
, RoomTypeName
FROM
rateplan_roomtypeTable
where
RateTypeId IN (select RateTypeId from ProductionTable where (cast(bookingdate as date) between date_add('day',-92, current_date) and date_add('day', -2, current_date)))
OR (isactiveRateType = 1 and isactiveRoomType = 1)
GROUP BY
1,2,3,4,5
Thank you

Performing some arithmetic operations inside a MySQL query on a subset of records

I have a MySQL table containing attendance records. Relevant columns identify attendees, sessions and attendance status (confirmed/declined/no-response). I also have a second table containing attendees' personal info, including the date they joined the group.
I am trying to build a single query that will output a list of all attendees, the number of times they attended sessions, and their regularity, expressed as the percentage of sessions they attended (against the total number of sessions). The problem is that total of sessions should only contains the sessions since the attendee joined the group.
So, for the first part, my query is:
SELECT name, count(*)
FROM attendance, members
WHERE attendance.attend = 2 and
attendance.member_number = members.number
GROUP BY attendance.member_number, attendance.attend
HAVING count(*) > 0
ORDER BY count(*) desc
This returns all attendees' names, plus the number of sessions each had attended. However, I'd also like to add that third column.
Thus, for each record, I first have to find out what was the members.member_since date, then query only the group of attendance records for each member, for which the dates are greater than member_since, get their count, then from that subset get the count where atteneance.attend = 2, then calculate what percentage of that subset count represents the second count (of records having attend = 2).
How do I write my query?
Data looks like this:
Table members:
number, name, join_date
001, Peter James, 2016-07-26
002, John Smith, 2014-06-04
TABLE attendance:
member_number, attend, date
001, 2, 2019-05-11
001, 1, 2019-05-04
001, 2, 2019-04-26
001, 2, 2019-04-18
002, 2, 2014-08-01
002, 1, 2016-08-01
002, 1, 2019-05-04
The desired result would be to get the following:
Name, Attended, percentage
Peter James, 3, 75%
John Smith, 1, 14%
In other words, while there were 6 sessions, Peter James has only been member for the last four, and attended 3 of them (75%), while John Smith has been a member since the beginning, so his attendance is one out of 6.
The structure is somewhat simplified (there is a 'sessions' table with details about sessions, including the date, and the 'attendance' table refers to its key column, 'att_number', rather than the actual date), but the point is the same.
Join the tables just on the dates to get the total number of sessions since the member joined. Then use a conditional SUM() to get the number of sessions that the member attended. Divide them to get the percentage.
SELECT m.name, SUM(m.number = a.member_number AND a.attend = 2) AS attendance, 100*SUM(m.number = a.member_number AND a.attend = 2)/COUNT(*) AS percent
FROM members AS m
JOIN attendance AS a ON a.date >= m.member_since
GROUP BY m.number
ORDER BY attendance DESC

Relational Database Logic

I'm fairly new to php / mysql programming and I'm having a hard time figuring out the logic for a relational database that I'm trying to build. Here's the problem:
I have different leaders who will be in charge of a store anytime between 9am and 9pm.
A customer who has visited the store can rate their experience on a scale of 1 to 5.
I'm building a site that will allow me to store the shifts that a leader worked as seen below.
When I hit submit, the site would take the data leaderName:"George", shiftTimeArray: 11am, 1pm, 6pm (from the example in the picture) and the shiftDate and send them to an SQL database.
Later, I want to be able to get the average score for a person by sending a query to mysql, retrieving all of the scores that that leader received and averaging them together. I know the code to build the forms and to perform the search. However, I'm having a hard time coming up with the logic for the tables that will relate the data. Currently, I have a mysql table called responses that contains the following fields,
leader_id
shift_date // contains the date that the leader worked
shift_time // contains the time that the leader worked
visit_date // contains the date that the survey/score was given
visit_time // contains the time that the survey/score was given
score // contains the actual score of the survey (1-5)
I enter the shifts that the leader works at the beginning of the week and then enter the survey scores in as they come in during the week.
So Here's the Question: What mysql tables and fields should I create to relate this data so that I can query a leader's name and get the average score from all of their surveys?
You want tables like:
Leader (leader_id, name, etc)
Shift (leader_id, shift_date, shift_time)
SurveyResult (visit_date, visit_time, score)
Note: omitted the surrogate primary keys for Shift and SurveyResult that I would probably include.
To query you join shifts and surveys group on leader and taking the average then jon that back to leader for a name.
The query might be something like (but I haven;t actually built it in MySQL to verify syntax)
SELECT name
,AverageScore
FROM Leader a
INNER JOIN (
SELECT leader_id
, AVG(score) AverageScore
FROM Shift
INNER JOIN
SurveyResult ON shift_date = visit_date
AND shift_time = visit_time --depends on how you are recording time what this really needs to be
GROUP BY leader ID
) b ON a.leader_id = b.leader_id
I would do the following structure:
leaders
id
name
leaders_timetabke (can be multiple per leader)
id,
leader_id
shift_datetime (I assume it stores date and hour here, minutes and seconds are always 0
survey_scores
id,
visit_datetime
score
SELECT l.id, l.name, AVG(s.score) FROM leaders l
INNER JOIN leaders_timetable lt ON lt.leader_id = l.id
INNER JOIN survey_scores s ON lt.shift_datetime=DATE_FORMAT('Y-m-d H:00:00', s.visit_datetime)
GROUP BY l.id
DATE_FORMAT here helps to cut hours and minutes from visit_datetime so that it could be matched against shift_datetime. This is MYSQL function, so if you use something else you'll need to use different function
Say you have a 'leader' who has 5 survey rows with scores 1, 2, 3, 4 and 5.
if you select all surveys from this leader, sum the survey scores and divide them by 5 (the total amount of surveys that this leader has). You will have the average, in this case 3.
(1 + 2 + 3 + 4 + 5) / 5 = 3
You wouldn't need to create any more tables or fields, you have what you need.

How to I find multiple logs in the same time interval?

I have a table with two columns of importance, customer ID# and timestamp. Whenever a customer orders something, five rows are created with the customer ID # and the timestamp of when it went through.
If there is more than five rows, it means our system hasn't processed the order correctly and there could be a problem, and I was asked to look through the log to find the customer IDs of any people who received more than 5, as well as how many times they received an incorrect amount and the number they received each time (when it was not 5)
I want it to show me, whenever the same customer ID (in column "ID") has more than 5 rows with the same timestamp (column "stamp") it will tell me 1. the person's customer ID 2. how many times this irregularity has happened to that customer ID, and 3. how many rows were in each irregularity (was it 6 or 7... or more? etc.) (if #2 was 3 times, I would like #3 to be an array like { 7, 8, 6 })
I don't know if this is possible... but any help at all will be appreciated. Thanks!
This should get you most of the way there:
SELECT `CustomerID`, `Timestamp`, COUNT(1)
FROM
OrderItems
GROUP BY
`CustomerID`, `Timestamp`
HAVING
COUNT(1) > 5
This will get you the IDs and Timestamps with more than 5 rows. I am making the assumption that the timestamps for all 5 (or more rows) are identical.
SELECT A.ID, A.TIMESTAMP
FROM "TABLE" A
WHERE
(SELECT COUNT(B.ID)
FROM "TABLE" B
WHERE B.ID = A.ID
AND B.TIMESTAMP = A.TIMESTAMP) > 5

Getting most similar rows in MySQL table and order them by similarity

I have a database table that holds user's vehicles (cars, motorcycles). I want to get the most similar vehicles out of that table. Lets say the table holds the following columns (with some context to get the idea):
table: vehicles
vehicle_id (pk, auto-increment)
model_id (BMW 3er, Honda Accord)
fuel_type (gasoline, diesel)
body_style (sedan, coupe)
year
engine_size (2.0L)
engine_power (150hp)
So in short I want to select N (usually 3) rows that have the same make_id (at least) and rank them by the amount of similarities they share with the seed vehicle lets say if the fuel_type matches, I'd have rank points +3, but if the body_style matches, it would be +1. Ideally I would get N vehicles that have maximum points but the idea is to still get something when I don't.
As in my table currently I have only around 5k rows and they are slowly growing, I decided to actually use the following simple approach (it came to me just after I wrote the question).
The seed lets say is Honda Accord (model_id 456), 2004, gasoline, 2.0L, 155hp, sedan with auto-inc ID 123.
SELECT vehicles.*,
(IF(`fuel_type`='gasoline', 3, 0) +
IF(`body_style`='sedan', 1, 0) +
IF(`year` > 2001 AND `year` < 2007, 2, 0) +
IF(`engine_size` >= 1.8 AND `engine_size` <= 2.2, 1, 0) +
IF(`engine_power`=155, 3, IF(`engine_power`>124 AND `engine_power`<186, 1, 0))) AS `rank`
FROM vehicles
WHERE vehicle_id!=123 AND model_id=456
ORDER BY `rank` DESC
LIMIT 3
It will work, as long as I don't too many rows. If the table becomes 50-100k, I probably will have to switch to something like Lucene?