SQL: Select a product based on minimum value of key - mysql

I'm looking for a way to select Category with lowest CustKey value as seen in below table 1. I want it to be displayed in a column called SignupCategory. I have also linked to my current SQL code which I cant make display the Category rather than the CustKey. I appreciate any suggestions as I am terribly stuck atm. Code is semi-dummy code. Note: Given that I have 10.000 CustomerIDs I would want all 10.000 customers SignupCategory.
Table 1:
| CustKey | CustomerID | Category |
|---------|------------|----------|
| 1 | Cust1 | Paying |
| 2 | Cust1 | Unpaying |
| 3 | Cust1 | Barred |
Result should show SignupCategory 'Paying'
SQL Code:
Select c.AgreementNumber, SignupCategory
FROM Customer c
Following is the WIP from another thread I found on stackoverflow:
INNER JOIN
(SELECT AgreementNumber, MIN(CustKey) As SignupCategory
FROM Customer
GROUP BY AgreementNumber, Category) X
ON c.AgreementNumber = X.AgreementNumber and c.Category = TRY_CONVERT(nvarchar,X.SignupCategory)
Following code works but displays CustKey (similar to what I found on stackoverflow):
INNER JOIN
(SELECT AgreementNumber, MIN(CustKey) As SignupCategory
FROM Customer
GROUP BY AgreementNumber) X
ON c.AgreementNumber = X.AgreementNumber AND c.CustKey = X.SignupCategory

For all customers respectively and if you have huge amount of data then use EXISTS instead of IN:-
SELECT category as SignupCategory FROM Customer WHERE CustKey IN (SELECT MIN(CustKey) FROM Customer group by CustomerID);

Related

Return preferred record when there is more than one record for the same user

I have a table where it stores the types of discounts that a user can have.
Some users will get the standard discount, but some will get a bigger and better discount. For users who have the biggest and best discount, there will be two records in the database, one for the default discount and the other for the biggest and best discount. The biggest and best discount will be preferred in the search.
I would like to do a SELECT that would return the record with the highest discount and if you don't find it, return it with the standard discount for me to avoid making two queries in the database or having to filter in the source code.
Ex:
| id | user_id | country | discount | cashback | free_trial |
|-----------------------------------------------------------------------|
| 1 | 1 | EUA | DEFAULT | 10 | false |
| 2 | 1 | EUA | CHRISTMAS | 20 | true |
| 3 | 3 | EUA | DEFAULT | 10 | false |
SELECT *
FROM users
WHERE country = 'EUA'
AND (discount = 'CHRISTMAS' OR discount = 'DEFAULT');
In this example above for user 1 it would return the record with the discount equal to "CHRISTMAS" and for user 3 it would return "DEFAULT" because it is the only one that has. Can you help me please?
You can use the row_number() window function to do this. This function includes a PARTITION BY that lets you start the numbering over with each user, as well as it's own ORDER BY that lets you determine which rows will sort first within each user/partition.
Then you nest this inside another SELECT to limit to rows where the row_number() result is 1 (the discount that sorted best):
SELECT *
FROM (
SELECT *, row_number() OVER (PARTITION BY id, ORDER BY cashback desc) rn
FROM users
WHERE country = 'EUA'
) u
WHERE rn = 1
You could also use a LATERAL JOIN, which is usually better than the correlated join in the other answer, but not as good as the window function.
You can using GROUP BY to do it
SELECT u1.*
FROM users u1
JOIN
(
SELECT COUNT(id) AS cnt,user_id
FROM users WHERE country = 'EUA'
GROUP BY user_id
) u2 ON u1.user_id=u2.user_id
WHERE IF(u2.cnt=1,u1.discount='DEFAULT',u1.discount='CHRISTMAS')
DB Fiddle Demo

MySQL query, two tables with order group by

I have two tables, bills and linesbill. I need all the products that a customer has ever bought. I've gotten this to work:
SELECT referencia, codcliente, pvpunitario, t2.fecha FROM
lineasfacturascli T1
INNER JOIN facturascli T2 ON T1.idfactura = T2.idfactura
WHERE T2.codcliente = "000001"
GROUP BY referencia
But I need get the last price that the customer has paid for each product. I'm trying to order by "fecha"->(date) but it does not work.
Tables structure
facturascli
idfactura(id bill),
codcliente(client id),
fecha(date)
lineasfacturascli
referencia(name of product),
idfactura(id bill)
pvpunitario(price)
Edit
DRapp solution works but I also need to handle the case that a customer buys it in the same day get only the lower price:
With the solution provided the result is:
|Referencia| |MostRecentDatePerItem| |MostRecentPricePerItem|
| pendrive | | 2017-03-02 | | 50 |
| pendrive | | 2017-03-02 | | 10 |
| samsung | | 2017-03-02 | | 50 |
| linux car| | 2017-04-26 | | 9.99 |
I need:
|Referencia| |MostRecentDatePerItem| |MostRecentPricePerItem|
| pendrive | | 2017-03-02 | | 10 |
| samsung | | 2017-03-02 | | 50 |
| linux car| | 2017-04-26 | | 9.99 |
Thanks
I would start with an inner pre-query of all line items for a specific person with a max date per item as a group by. So if a person ordered the 10 things multiple times over say... 50 orders, you would still have the final list of 10 things, but also the most recent date the thing was ordered.
The following is based on not exactly knowing your structures, nor sample data (please provide for future). Also, you should always qualify your table columns in a query with the corresponding table alias reference so users know which field comes from what table. I have to assume the "pvpunitario" column is from the line item details as the price, but basic translation appears to be "unit" not price. You will have to adjust accordingly if I am inaccurate on my impression.
select
T1.referencia,
max( t2.fecha ) as MostRecentDatePerItem
FROM
lineasfacturascli T1
INNER JOIN facturascli T2
ON T1.idfactura = T2.idfactura
WHERE
T2.codcliente = "000001"
GROUP BY
T1.referencia
So this will give us just the products and the maximum date ever ordered by a single client. Now, we take this result as a basis to the original query, re-joined to the line items / order headers that specifically match the corresponding MostRecentDatePerItem.
select
TT1.Referencia,
PQ.MostRecentDatePerItem,
TT1.pvpunitario as MostRecentPricePerItem
from
lineasfacturascli TT1
JOIN
(select
T1.referencia,
max( t2.fecha ) as MostRecentDatePerItem
FROM
lineasfacturascli T1
INNER JOIN facturascli T2
ON T1.idfactura = T2.idfactura
WHERE
T2.codcliente = "000001"
GROUP BY
T1.referencia ) PQ
on TT1.Referencia = PQ.Referencia
JOIN facturascli TT2
ON TT1.idfactura = TT2.idfactura
AND PQ.MostRecentDatePerItem = TT2.Fecha
where
TT2.codcliente = "000001"
To clarify what is going on. The inner query (now alias "PQ" -- PreQuery), is just those qualifying items for the one client in question with the most recent date said item was purchased.
So now back to the original list of all order line items joined to this table keeps the reference product ID linked. Now, we go again to the order header table and still apply the same client code, but ALSO joined on the same FETCHA date as the maximum date found for the transaction. So only THEN do we want to grab the detail level price / unit information for said product.
Hopefully this helps direct your final solution. If I am incorrect on any pieces, you should EDIT your original question and supply the additional missing details / alias references / sample data. Then you can reply comment for follow-up support.
Answer per Comment.
To get the minimum price, you would just adjust the outer select and add a group by. Since the item is the same, the group by will only group for the prices on that specific day. Change the above to...
select
TT1.Referencia,
PQ.MostRecentDatePerItem,
MIN( TT1.pvpunitario ) as LeastPricePerItemOnThisDate
(same rest of query)
GROUP BY
TT1.Referencia,
PQ.MostRecentDatePerItem

mysql using limit in a left join not working properly

I have two tables looking like this
Patient (table 1)
id | name
------------
1 | robel
2 | dave
Patient_followup (table 2)
id | Patient_id | date_created
-----------------------
1 | ---- 1 -- | 01/01/2015
2 | -----1 -- | 01/07/2016
I want to display all the patients with their perspective latest followup data. so i tried using this query
Select * from patient
left join Patient_followup pf on pf.Patient_id = patient.id
order by pf.date_created
Limit 1
but this is giving me only the first patient robel. i tryed removing the limit and its giving me two records of robel and one record of dave because robel has two followup data. so what should i do to get only one record of each patient ?
Try this:
Select
*
from
patient
left join
(SELECT
id as pf_id,
MAX(date_created) as latest_followup_date,
Patient_id
FROM
Patient_followup
GROUP BY
Patient_id) as pf
ON pf.Patient_id = patient.id
As mentioned by anton in the first comment, you need to use aggregation to get one record per patient.
Select patient.*,MAX(pf.date_created) as followupdate,group_concat(pf.date_created) from patient
left join Patient_followup pf on pf.Patient_id = p.patient.id
group by patient.id
order by pf.date_created
Here, you will get your values comma separated.
1) "Limit 1" will only return the first result. Typically this is used if the query will result in a very large result set and you only want the first few results.
Ex:
"LIMIT 30" will show the first 30 rows of the query.
2) I would change to setup of the tables so the query is smoother. Right now, you create a new line for each follow-up date even if the patient is already created. You could add another column in the table named "FollowUpDate". That way each patient record has the table id, patient id, creation date and followup date in the same row. That way, each patient has only one row.
EX:
Patient (table 1)
id | name | created_date | next_followup_date |
1 | Robel | 01/01/2015 | 01/01/2016 |
2 | Dave |[created_date]| [next_follup_date] |
Patient_followup (table 2)
id | Patient_id | date_created | followUpDate |
1 | 1 | 01/01/2015 | 06/01/2016 | // example date
2 | 1 | 01/01/2015 | 01/01/2016 |
3 | 2 |[date created]| [FollowUpDate] |
3) Change query to:
Use this select statement to get all patient records.
Select * from patient
left join Patient_followup pf on pf.Patient_id = patient.id
order by pf.Patient_id
Use this select statement to get the specific patient record information.
Select * from patient
inner join Patient_followup pf on pf.Patient_id = patient.id
where patient.id = 1 //to get robel. Edit this line as necessary, perhaps by user input...
order by pf.followUpDate
NOTE: When you insert a new record in Patient_followup, make sure you update Patient.next_followup_date.
I hope this helps!

Update table with data from multiple tables

I'm stuck on this one. I have three tables:
Table 1:
**ORDERS**
| ORDER_NO | PRODUCT_NO | CLIENT_NO | UNITS | ORDER_DATE |
Table 2:
**CLIENTS**
| CLIENT_NO | NAME | LOCATION | SELLER_NO | OWES | OVERPAID | CREDIT_LIMIT |
Table 3:
**PRODUCTS**
| PRODUCT_NO | DESCRIPTION | UNIT_PRICE | AVAILABLE_STOCK |
Now, what I have to do is to update column OWES in table CLIENTS so it contains total amount of money of all the orders they made.
This is as far as I got:
update CLIENTS set OWES = (select sum(o.UNITS) from ORDERS o where CLIENTS.CLIENT_NO = o.CLIENT_NO);
That seems to work just fine to get a total number of orders, but than I have to multiply it by the price of given item (whichever the order was for) and I get myself confused.
I tried for example:
update CLIENTS set OWES = ( select sum(o.UNITS) from ORDERS o where CLIENTS.CLIENT_NO = o.CLIENT_NO)*(select UNIT_PRICE from PRODUCTS where PRODUCT_NO= any(select PRODUCT_NO from ORDERS));
But that returns ERROR 1242 (21000): Subquery returns more than 1 row
What am I doing wrong? Would it be better to use update CLIENTS as ( some complicated sub query goes here) ?
Can anyone help me out and be so kind to throw in some explanation why such solution and not some other? It just seem like I didn't get something on more basic level and now I'm struggling.
Thanks in advance.
I think you can just do a join in the subquery and do the appropriate aggregation:
update CLIENTS
set OWES = (select sum(o.UNITS * p.unit_price)
from ORDERS o join
products p
on o.product_no = p.product_no
where CLIENTS.CLIENT_NO = o.CLIENT_NO
);
Your syntax is a little off. The general syntax for updating from other tables is:
UPDATE table1
JOIN table2 ON table2.mycolumn = table1.mycolumn
JOIN (
SELECT foo, SUM(bar) as sumbar FROM table3) table3sum ON table3sum.foo = table1.foo
SET
table1.foo = table2.bar,
table1.baz = table3sum.sumbar

getting count of each category filtered by another table's field

I have tables with the following structure.
AD_TABLE -
ID|NAME|CAT_ID|TYPE
1| car | C0101|Sale
2|bike | C0201|Want
CAT_TABLE -
ID |NAME |PARENT|LEVEL
C0100|Vehicle |C0100 | 0
C0101|Car |C0100 | 1
C0200|Bike/Scooters |C0100 | 1
C0201|Bike |C0200 | 2
C0202|Scooter |C0200 | 2
I need to get the count of ADs from each category, I have written the following query.
SELECT `CAT_TABLE`.`ID`,`CAT_TABLE`.`NAME`,`CAT_TABLE`.`LEVEL`,`CAT_TABLE`.`PARENT`, COUNT(`AD_TABLE`.`ID`)
FROM `CAT_TABLE`
LEFT JOIN `AD_TABLE` ON `AD_TABLE`.`CAT_ID`=`CAT_TABLE`.`ID`
WHERE (`CAT_TABLE`.`ID`='C0100' OR `CAT_TABLE`.`PARENT`='C0100') AND `AD_TABLE`.`TYPE`='0'
GROUP BY `CAT_TABLE`.`ID`
I got the count of each categories properly but after including the AD_TABLE.TYPE`='0' in the where clause categories which do not have ADs were ignored. I need to get all the categories even if the count is 0.
try this
SELECT `CAT_TABLE`.`ID`,`CAT_TABLE`.`NAME`,`CAT_TABLE`.`LEVEL`,`CAT_TABLE`.`PARENT`, COUNT(`AD_TABLE`.`ID`)
FROM `CAT_TABLE`
LEFT JOIN `AD_TABLE`
ON `AD_TABLE`.`CAT_ID`=`CAT_TABLE`.`ID`
AND `AD_TABLE`.`TYPE`='0' -- Write and here..<br/>
WHERE (`CAT_TABLE`.`ID`='C0100' OR `CAT_TABLE`.`PARENT`='C0100')
GROUP BY `CAT_TABLE`.`ID`