Compare rows in same table in mysql - mysql

I have a mysql table like below
id trader price
111 abc 5
222 xyz 5.20
333 abc 5.70
444 xyz 5
555 abc 5.20
I need to compare row 1's price with row 2's price and accroding to the given sample row 2's price is less than row 1's price which means that trader xyz increased the price once, and in the same way when we compare row 2's price with row 3's price where row 3's price is higher than row 2's price which means trader abc also increased the price once. So in this manner I need to compare the entire table and find how many times each trader increased or decreased price...
I dont have any idea to do this, can someone please help me on this

You can perform a "self-join" (joining the table to itself) to perform queries. The tricky part here is knowing the order in which rows were inserted into the table, and only comparing rows that are sequentially (temporally) adjacent. I'm assuming you have some sort of TIMESTAMP column that will tell you which price changes came after the prior ones. If not, then perhaps "ID" can inform you of that (the greater ID row being inserted after the lesser ID).
Calling your table 'TAB', using 'TRADER' to provide the join, and using 'ID' to provide the Order, the query would require a three-way self-join such as follows:
SELECT a.trader
, SUM(IF(a.price > b.price, 1, 0)) nbr_incr
, SUM(IF(a.price < b.price, 1, 0)) nbr_decr
, SUM(IF(a.price = b.price, 1, 0)) nbr_same
FROM tab a
JOIN tab b
ON a.trader = b.trader AND a.id > b.id
LEFT OUTER JOIN tab c
ON a.trader = c.trader AND a.id > c.id AND b.id < c.id
WHERE c.id IS NULL
GROUP BY a.trader
The above query joins the table to itself twice so that each tab represents the following:
tab a : The more recent row for comparison
tab b : The immediately prior row to compare against
tab c : A row between a & b timewise (should not exist)
We perform a LEFT OUTER JOIN to 'tab c' because we do not actually want that row to exist. In the where clause, we filter our results only to the results where a 'tab c' row does not exist.
Finally, the query performs a 'GROUP BY' on the trader, and SUM()s the Increments and Decrements by comparing the price from the 'a' and 'b' rows.
This was a fun challenge. Hope this helps!
john...

You will need to setup a separate table if you want to track a history of price changes. Also, when you refer to columns, it sounds like you mean rows.

Related

How to check all stock status and mark as "Sold Out" or "In Stock"

I have 3 table that contain product, product_design and design_type. I'm trying to query out data that have both sold out and in stock product under specific condition where if all stock under design X is 0 then mark as 'OUT_OF_STOCK' otherwise 'IN_STOCK'.
Product Table
Product_design Table
Design_type Table
SELECT a.pid, b.did, a.p_name, a.discount_price, a.original_price, a.p_description, a.p_viewable, c.t_stock, c.t_name,
(CASE WHEN c.t_stock='0' THEN 'OUT_OF_STOCK' ELSE 'IN_STOCK' END) AS stock_status
FROM product a, product_design b, design_type c
WHERE a.pid=b.pid and c.did=b.did and a.p_viewable='Y'
GROUP BY a.pid;
output
Based on the output above, the stock_status of pid=22 should be 'IN_STOCK' because there is design under that pid still have stocks.
All design under pid=22
I'm trying to get the correct stock status.
I think the problem might be that it is checking the first c.t_stock it finds, since there is a t_stock for each instance of that product. Maybe try using the SUM function (sum of c.t_stock). That way if sum = 0, we are sure that all of t_stock are zero.

How to add a tag based on a column value

I'm trying to join two tables and select certain columns to display in the output including a 'flag' if a certain transaction amount is greater than or equal to 100. The flag would return a 1 if it is, else null.
I thought I could achieve this using a CASE in my SELECT but it only returns one record every time since it returns the first record that meets this condition. How do I just create this 'FLAG' column during my join easily?
SELECT payment_id, amount, type,
CASE
WHEN amount >= 100 THEN 1
ELSE NULL
END AS flag
FROM trans JOIN customers ON (user_id = cust_id)
JOIN bank ON (trans.bank = bank.id)
WHERE (error is false)
I expect an output such as:
payment_id amount type flag
1 81 3 NULL
2 104 2 1
3 150 2 1
4 234 1 1
However, I'm only getting the first record such as:
payment_id amount type flag
2 104 2 1
I tried your table structure in my local and it is working perfectly.
I need one thing from you is in which table you are having error column.
If I comment where condition then it is working fine.
If you're getting fewer rows than you expect, it's either due to:
Join condition
You're doing a INNER joins to the customers and bank tables. If you have 4 source rows in your trans table, but only one row that matches in your customers table (condition user_id = cust_id), then you will only have one row returned.
The same goes for the subsequent join to your bank table. If there you somehow have a transaction that references a bank which is not defined in the bank table, then you won't see a record for this row.
WHERE clause
Obviously you won't see any rows that don't meet the conditions specified here.
It's probably #1 -- check to see if the rows with payment_id IN (1,3,4) have corresponding user id values in the user table and corresponding bank id values in the banks table.

SQL Validate a column with the same column

I have the following situation. I have a table with all info of article. I will like to compare the same column with it self. because I have multiple type of article. Single product and Master product. the only way that I have to differences it, is by SKU. for example.
ID | SKU
1 | 11111
2 | 11112
3 | 11113
4 | 11113-5
5 | 11113-8
6 | 11114
7 | 11115
8 | 11115-1-W
9 | 11115-2
10 | 11116
I only want to list or / and count only the sku that are full unique. follow th example the sku that are unique and no have variant are (ID = 1, 2, 6 and 10) I will want to create a query where if 11113 are again on the column not cout it. so in total I will be 4 unique sku and not "6 (on total)". Please let me know. if this are possible.
Assuming the length of master SKUs are 5 characters, try this:
select a.*
from mytable a
left join mytable b on b.sku like concat(a.sku, '%')
where length(a.sku) = 5
and b.sku is null
This query joins master SKUs to child ones, but filters out successful joins - leaving only solitary master SKUs.
You can do this by grouping and counting the unique rows.
First, we will need to take your table and add a new column, MasterSKU. This will be the first five characters of the SKU column. Once we have the MasterSKU, we can then GROUP BY it. This will bundle together all of the rows having the same MasterSKU. Once we are grouping we get access to aggregate functions like COUNT(). We will use that function to count the number of rows for each MasterSKU. Then, we will filter out any rows that have a COUNT() over 1. That will leave you with only the unique rows remaining.
Take that unique list and LEFT JOIN it back into your original table to grab the IDs.
SELECT ID, A.MasterSKU
FROM (
SELECT
MasterSKU = SUBSTRING(SKU,1,5),
MasterSKUCount = COUNT(*)
FROM MyTable
GROUP BY SUBSTRING(SKU,1,5)
HAVING COUNT(*) = 1
) AS A
LEFT JOIN (
SELECT
ID,
MasterSKU = SUBSTRING(SKU,1,5)
FROM MyTable
) AS B
ON A.MasterSKU = B.MasterSKU
Now one thing I noticed from you example. The original SKU column really looks like three columns in one. We have multiple values being joined with hypens.
11115-1-W
There may be a reason for it, but most likely this violates first normal form and will make the database hard to query. It's part of the reason why such a complicated query is needed. If the SKU column really represents multiple things then we may want to consider breaking it out into MasterSKU, Version, and Color or whatever each hyphen represents.

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

Help diagnose bizzare MySQL query behavior

I have a very specific query that is acting up and I could use any help at all with debugging it.
There are 4 tables involved in this query.
Transaction_Type
Transaction_ID (primary)
Transaction_amount
Transaction_Type
Transaction
Transaction_ID (primary)
Timestamp
Purchase
Transaction_ID
Item_ID
Item
Item_ID
Client_ID
Lets say there is a transaction in which someone pays $20 in cash and $0 in credit it inserts two rows into the table.
//row 1
Transaction_ID: 1
Transaction_amount: 20.00
Transaction_type: cash
//row 2
Transaction_ID: 1
Transaction_amount: 0.00
Transaction_type: credit
here is the specific query:
SELECT
tt.Transaction_Amount, tt.Transaction_ID
FROM
ItemTracker_dbo.Transaction_Type tt
JOIN
ItemTracker_dbo.Transaction t
ON
tt.Transaction_ID = t.Transaction_ID
JOIN
ItemTracker_dbo.Purchase p
ON
p.Transaction_ID = tt.Transaction_ID
JOIN
ItemTracker_dbo.Item i
ON
i.Item_ID = p.Item_ID
WHERE
t.TimeStamp >= "2010-01-06 00:00:00" AND t.TimeStamp <= "2010-01-06 23:59:59"
AND
tt.Transaction_Format IN ('cash', 'credit')
AND
i.Client_ID = 3
when I execute this query, it returns 4 rows for a specific transaction. (it should be 2)
When I remove ALL where clauses and insert WHERE tt.Transaction_ID = problematicID it only returns two.
EDIT:::::
still repeats upon changing date range
The kicker:
When I change the initial daterange it only returns two rows for that specific transaction_id.
::::
Is it the way I use join? that's all I can think of...
EDIT: This is the problem
in purchase - two sepparate purchase_ID's can have the same transaction_ID (purhcase_ID breaks down specific item sales).
There are duplicate Transaction_ID rows in purchase_ID
We need to see all the data in all the tables to be able to know where the problem is. However, because the joins are the problem it is because one of your tables has two rows when you think it has only one.
There's a problem with your schema. You have rows with the same transaction_id, which is the primary key. I would think they couldn't be marked primary in that database. With two rows with the same id, that could cause unexpected extra rows to come back from the join(s).