I have a table called order_status_log, which logs who changed order statuses.
Simplified table and query below:
order_id user_id status time
1 1 1 2016-01-27 19:35:44
2 2 2 2016-01-27 19:36:45
4 3 2 2016-01-27 19:37:43
2 1 5 2016-01-27 19:38:41
I also have SQL which counts changes by each user:
SELECT
COUNT(*) as count,
user_id
FROM order_status_log
WHERE status = 1
GROUP BY user_id
ORDER BY count
Now I want to improve my query to count only first status changes in order.
In other words I need unique order_id with older time.
How I can change my query to do that?
Something like this?
SELECT *
FROM order_status_log o
WHERE NOT EXISTS
( SELECT 'x'
FROM order_status_log o2
WHERE o2.user_id = o.user_id
AND o2.time < o.time)
Related
I have this table
**applications**
id user_id company_id shortlisted
1 10 99 0
2 10 100 1
3 10 101 1
4 10 102 0
5 11 99 1
6 12 99 0
6 12 101 0
What I want is to select all users
which have been shortlisted at-least once
which have not been shortlisted at all
For the first case, i have the following query:
SELECT user_id
from applications
where shortlisted=1
Group
By user_id
and this gives me the expected result like below
**applications**
user_id
10
11
But I'm trying the following query for the second case and it returns me an empty set:
Select user_id
from applications as Application
where shortlisted=0
and NOT EXISTS(Select user_id from applications where user_id=Application.user_id and shortlisted=1)
What am i missing?
PS: Please ignore any typos as i typed them manually for this post.
To get both results in a single query simply use aggregation:
select user_id, max(shortlisted) as was_shortlisted
from applications
group By user_id
You can use group by and having for both.
For the first:
select user_id
from applications
group By user_id
having max(shortlisted) = 1;
For the second:
select user_id
from applications
group By user_id
having max(shortlisted) = 0;
In all honesty, your version with the where is more efficient for the first query. This is just to show how closely related the queries are.
You can try following query;
select user_id from table1
group by user_id having MIN(shortlisted) = 1
This will give you to at least have shortlisted = 1 condition and don't have shortlisted = 0 records.
I have the following tables:
Table users
id name base_discount
1 jack 10
2 michael 20
3 richard 30
Table item
id name category_id price
1 hammer 1 10
2 knife 2 15
3 spoon 2 12
4 plate 3 20
5 tree 4 400
Table category
id name
1 tools
2 kitchen
3 dishes
4 garden
Table discount_category
id user_id category_id discount
1 1 1 20
2 1 3 25
3 3 3 10
4 1 2 15
Table discount_item
id user_id item_id discount
1 2 1 50
2 1 2 50
Now what I want to achieve. I want to attach the discount per item that a user has to the correct item. If that is not available (NULL) I want to attach the discount per category that a user has. And if that is not available (NULL), I want to attach the base discount that a user has. With the discount I then calculate the new price of the item. However, when I try using COALESCE() within SUM() I get a syntax error. What am I doing wrong?
Below is my current query:
SELECT item.id, item.name, category.id,
category.name AS category_name, item.price, SUM((100 -
COALESCE(
(
SELECT discount_item.discount
FROM discount_item
INNER JOIN users ON discount_item.user_id = users.id
WHERE users.id = '1' AND discount_item.item_id = item.id
),
(
SELECT discount_category.discount
FROM discount_category
INNER JOIN users ON discount_category.user_id = users.id
WHERE users.id = '1' AND discount_category.category_id = item.category_id
),
(
SELECT users.base_discount
FROM users
WHERE users.id = '1'
)
)) / 100 * item.price) AS new_price,
FROM item
INNER JOIN category ON item.category_id = category.id;
Please also see the below link for an SQL Fiddle (couldn't do it on sqlfiddle.com as it wouldn't load). In the example I have appended a suffix to each table name.
http://rextester.com/LCCKSD59098
You have an extra comma after new_price and before FROM ITEM, hence the error.
Rextester Demo
Do not select other columns in select if you are not using them in group by, as in other relational RDBMS, you will get error.
Also use alias for table names for better readibily and to avoid confusion.
I know this sounds a little bit strange but I don't really know how to explain this better without an example.
I have the following table
ID contract_id status_id created
1 1 1 2015-10-14
2 1 2 2015-10-15
3 1 1 2016-02-02
4 1 4 2017-03-01
If the query is something like
SELECT * FROM table WHERE status_id = 1 AND created BETWEEN 2015-10-10 AND 2017-03-05
The item with contract_id = 1 should not display because the latest status in that date interval is 4
But if the query is something like this
SELECT * FROM table WHERE status_id = 1 AND created BETWEEN 2015-10-10 AND 2017-02-28 the item with contract_id 1 should show up because the latest status_id = 1
Basically what I need is something like this: Get me the latest item if the status_id = 1 at the end date
I know this is quite simple but I running around in circles right now. I did try abs(datediff(end, start)), select based on if or select in select but I am not getting the result I am looking for.
Thank you very much for your help.
One of the approaches would be to use an INNER JOIN of the latest date a given contract_id had the required status, and test if the date is earlier than the border date:
EDIT: After further reading the comments, most probably this one will do exactly what you need
SELECT t.*
FROM statuses AS t
INNER JOIN (
SELECT max(id) AS lastid, max(created) AS lastdate
FROM statuses
WHERE status_id = 1 AND created < '2016-01-01'
GROUP BY contract_id
) AS latest ON t.ID = latest.lastid
Note that it will work only if the dates are put in chronologically, in other words that for every contract_id: ID' < ID'' ≡ created' < created''
Oracle :
SELECT * FROM table WHERE status_id = 1 AND created BETWEEN 2015-10-10 AND 2017-03-05 AND ROWNUM <=1 ORDER BY created desc
MySQL :
SELECT * FROM table WHERE status_id = 1 AND created BETWEEN 2015-10-10 AND 2017-03-05 ORDER BY created desc LIMIT 1
SQL Server :
SELECT TOP 1 FROM table WHERE status_id = 1 AND created BETWEEN 2015-10-10 AND 2017-03-05 ORDER BY created desc
I understood your question as that you want an item with status_id = 1 and which has most recent created date
I have a 'billing' table which represent all instances of billings from my subscribers. A subscriber can have multiple billings.
I have a simple SQL request which is :
SELECT count(billing_id),subscriber_id
FROM billing
group by subscriber_id
As a result I have a list of all my subscribers with the number of billings they've made.
I want to have a list of all the billings no grouped by subscribers, but I want the result of the previous request appearing in each lines.
Example:
Result of my previous request:
sub_id nb_billings
1 3
2 2
What I want :
sub_id nb_billings
1 3
1 3
1 3
2 2
2 2
Thanks
I'd do it like this;
SELECT
b.subscriber_id
,a.billing_count
FROM billing b
JOIN (SELECT subscriber_id, count(billing_id) billing_count FROM billing GROUP BY subscriber_id) a
ON b.subscriber_id = a.subscriber_id
The subquery works out the count of billing_id by subscriber, this is then joined to all rows of your original table (using subscriber_id). This should give the result you're after.
You can use a subquery to do that:
SELECT
(SELECT count(t2.billing_id) FROM billing t2 WHERE t2.subscriber_id = t1.subscriber_id),
t1.subscriber_id
FROM billing t1
I guess this should suffice :
SELECT s.subscriber_id,
s.billing_id,
s.TotalCount
FROM (
SELECT subscriber_id,
billing_id,
COUNT(billing_id) AS TotalCount
FROM BILLING
GROUP BY subscriber_id,
billing_id
) s
GROUP BY s.subscriber_id,
s.TotalCount,
s.billing_id
ORDER BY s.subscriber_id
This should give you the result as follows :
subscriber_id billing_id TotalCount
1 10a 2
1 10b 2
1 10c 1
2 10a 1
2 10b 1
2 10c 3
2 10d 1
You can see this here -> http://rextester.com/AVVS23801
Hope this helps!!
select subscriber_id,count(billing_id)over(partition by subscriber_id)
from billing
will do just that.
I have simple table:
Order_ID Client_ID Date Order_Status
1 1 01/01/2015 3
2 2 05/01/2015 3
3 1 06/01/2015 3
4 2 10/01/2015 3
5 1 12/01/2015 4
6 1 05/02/2015 3
I want to identify orders from new customers which are orders in same month in which that customer made first order with Order_Status = 3
So the output table should look like this:
Order_ID Client_ID Date Order_Status Order_from_new_customer
1 1 01/01/2015 3 yes
2 2 05/01/2015 3 yes
3 1 06/01/2015 3 yes
4 2 10/01/2015 3 yes
5 1 12/01/2015 4 NULL
6 1 05/02/2015 3 no
I wasn't able to successfully figure out the query. Thanks a lot for any help.
Join with a subquery that gets the date of the first order by each customer.
SELECT o.*, IF(MONTH(o.date) = MONTH(f.date) AND YEAR(o.date) = YEAR(f.date),
'yes', 'no') AS order_from_new_customer
FROM orders AS o
JOIN (SELECT Client_ID, MIN(date) AS date
FROM orders
WHERE Order_Status = 3
GROUP BY Client_ID) AS f
ON o.Client_ID = f.Client_ID
Use a CASE statement along with a SELF JOIN like below
select t1.*,
case when t1.Order_Status = 3 and MONTH(t1.`date`) = 1 then 'yes'
when t1.Order_Status = 3 and MONTH(t1.`date`) <> 1 then 'no'
else null end as Order_from_new_customer
from order_table t1 join order_table t2
on t1.Order_ID < t2.Order_ID
and t1.Client_ID = t2.Client_ID;
If your order table gets big, the solutions from Rahul and Barmar will tend to get slow.
I would hope your shop will get many orders and you will run into performance trouble ;-). So I would suggest marking the very first order of a new customer with a tinyint column, and when you have the comfort of a tinyint, you could code it like:
0 : unknown
1 : very first order
2 : order in first month
3 : order in "grown-up" mode.
The very first order you could probably mark easily, everyone loves a bright new customer enough to store this event somehow during first ordering. The other orders you can identify in a background job / cronjob by there "0" for unknown, or you mark your old customers and store the "3" on their orders.
The result-set can be achieved without any table-join or subquery:
select
if(Order_Status<>3,null,if(#first_date:=if(#prev_client_id!=Client_ID,month(date),#first_date)=month(date),"yes","no")) as Order_from_new_customer
,Order_ID,Client_ID,date,Order_Status,#prev_client_id:=client_id
from
t1,
(select #prev_client_id:="",#first_date:="")t
order by Client_ID ,date
One extra column added for computation and order by clause is used.
Verify result at http://sqlfiddle.com/#!9/83c29f/24