Make column value as a row - mysql

I'm not sure I titled the question correctly, I'll try to explain what I mean by example.
I have the following query:
SELECT
d.name_ascii,
d.price,
t.whois_price
FROM domain d
JOIN tld t ON d.tld_id = t.id
JOIN user_tld ut ON t.id = ut.tld_id
WHERE ut.user_id = 1
AND d.name_ascii IN ('domain.com')
which returns the following:
+------------+---------+-------------+
| name_ascii | price | whois_price |
+------------+---------+-------------+
| domain.com | 321.000 | 15.000 |
+------------+---------+-------------+
It's ok, but I need next result:
+------------------+---------+
| item | price |
+------------------+---------+
| domain.com | 321.000 |
| domain.com whois | 15.000 |
+------------------+---------+
That is I need to remove 3-rd column named whois_price and insert it as another row with the same price value and concatenated name_ascii value with "whois" as item column.
I have no idea how to solve it. Any advice, hint?
Thanks!

One way to accomplish this would be with a UNION.
SELECT
d.name_ascii as item,
d.price
FROM domain d
WHERE d.name_ascii IN ('domain.com')
UNION ALL
SELECT
concat(d.name_ascii,' whois'),
t.whois_price
FROM domain d
JOIN tld t ON d.tld_id = t.id
JOIN user_tld ut ON t.id = ut.tld_id
WHERE ut.user_id = 1
AND d.name_ascii IN ('domain.com')
The first part gets price, the second part gets the whois price.
Here's a SQL Fiddle: http://sqlfiddle.com/#!9/d5164/3

Related

SQL: Select a product based on minimum value of key

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);

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!

Issue with mysql query that calls column name from another table

I have two tables, one is an index (or map) which helps when other when pulling queries.
SELECT v.*
FROM smv_ v
WHERE (SELECT p.network
FROM providers p
WHERE p.provider_id = v.provider_id) = 'RUU='
AND (SELECT p.va
FROM providers p
WHERE p.provider_id = v.provider_id) = 'MjU='
LIMIT 1;
Because we do not know the name of the column that holds the main data, we need to look it up, using the provider_id which is in both tables, and then query.
I am not getting any errors, but also no data back. I have spent the past hour trying to put this on sqlfiddle, but it kept crashing, so I just wanted to check if my code is really wrong, hence the crashing?
In the above example, I am looking in the providers table for column network, where the provider_id matches, and then use that as the column on smv.
I am sure i have done this before just like this, but after the weekend trying I thought i would ask on here.
Thanks in Advance.
UPDATE
Here is an example of the data:
THis is the providers, this links so no matter what the name of the column on the smv table, we can link them.
+---+---+---------------+---------+-------+--------+-----+-------+--------+
| | A | B | C | D | E | F | G | H |
+---+---+---------------+---------+-------+--------+-----+-------+--------+
| 1 | 1 | Home | network | batch | bs | bp | va | bex |
| 2 | 2 | Recharge | code | id | serial | pin | value | expire |
+---+---+---------------+---------+-------+--------+-----+-------+--------+
In the example above, G will mean in the smv column for recharge we be value. So that is what we would look for in our WHERE clause.
Here is the smv table:
+---+---+-----------+-----------+---+----+---------------------+-----+--+
| | A | B | C | D | E | F | value | va |
+---+---+-----------+-----------+---+----+---------------------+-----+--+
| 1 | 1 | X2 | Home | 4 | 10 | 2016-09-26 15:20:58 | | 7 |
| 2 | 2 | X2 | Recharge | 4 | 11 | 2016-09-26 15:20:58 | 9 | |
+---+---+-----------+-----------+---+----+---------------------+-----+--+
value in the same example as above would be 9, or 'RUU=' decoded.
So we do not know the name of the rows, until the row from smv is called, once we have this, we can look up what column name we need to get the correct information.
Hope this helps.
MORE INFO
At the point of triggering, we do not know what the row consists of the right data because some many of the fields would be empty. The map is there to help we query the right column, to get the right row (smv grows over time depending on whats uploaded.)
1) SELECT p.va FROM providers p WHERE p.network = 'Recharge' ;
2) SELECT s.* FROM smv s, providers p WHERE p.network = 'Recharge';
1) gives me the correct column I need to look up and query smv, using the above examples it would come back with "value". So I need to now look up, within the smv table, C = Recharge, and value = '9'. This should bring me back row 2 of the smv table.
So individually both 1 and 2 queries work, but I need them put together so the query is done on the database server.
Hope this gives more insight
Even More Info
From reading other posts, which are not really doing what I need, i have come up with this:
SELECT s.*
FROM (SELECT
(SELECT p.va
FROM dh_smv_providers p
WHERE p.provider_name = 'vodaphone'
LIMIT 1) AS net,
(SELECT p.bex
FROM dh_smv_providers p
WHERE p.provider_name = 'vodaphone'
LIMIT 1) AS bex
FROM dh_smv_providers) AS val, dh_smv_ s
WHERE s.provider_id = 'vodaphone' AND net = '20'
ORDER BY from_base64(val.bex) DESC;
The above comes back blank, but if i replace net, in the WHERE clause with a column I know exists, I do get the results expected:
SELECT s.*
FROM (SELECT
(SELECT p.va
FROM dh_smv_providers p
WHERE p.provider_name = 'vodaphone'
LIMIT 1) AS net,
(SELECT p.bex
FROM dh_smv_providers p
WHERE p.provider_name = 'vodaphone'
LIMIT 1) AS bex
FROM dh_smv_providers) AS val, dh_smv_ s
WHERE s.provider_id = 'vodaphone' AND value = '20'
ORDER BY from_base64(val.bex) DESC;
So what I am doing wrong, which is net, not showing the value derived from the subquery "value" ?
Thanks
SELECT
v.*,
p.network, p.va
FROM
smv_ v
INNER JOIN
providers p ON p.provider_id = v.provider_id
WHERE
p.network = 'RUU=' AND p.va = 'MjU='
LIMIT 1;
The tables talk to each other via the JOIN syntax. This completely circumvents the need (and limitations) of sub-selects.
The INNER JOIN means that only fully successful matches are returned, you may need to adjust this type of join for your situation but the SQL will return a row of all v columns where p.va = MjU and p.network = RUU and p.provider_id = v.provider_id.
What I was trying to explain in comments is that subqueries do not have any knowledge of their outer query:
SELECT *
FROM a
WHERE (SELECT * FROM b WHERE a)
AND (SELECT * FROM c WHERE a OR b)
This layout (as you have in your question) is that b knows nothing about a because the b query is executed first, then the c query, then finally the a query. So your original query is looking for WHERE p.provider_id = v.provider_id but v has not yet been defined so the result is false.

MySQL subquery from same table

I have a database with table xxx_facileforms_forms, xxx_facileforms_records and xxx_facileforms_subrecords.
Column headers for xxx_facileforms_subrecords:
id | record | element | title | neame | type | value
As far as filtering records with element = '101' ..query returns proper records, but when i add subquery to filete aditional element = '4871' from same table - 0 records returned.
SELECT
F.id AS form_id,
R.id AS record_id,
PV.value AS prim_val,
COUNT(PV.value) AS count
FROM
xxx_facileforms_forms AS F
INNER JOIN xxx_facileforms_records AS R ON F.id = R.form
INNER JOIN xxx_facileforms_subrecords AS PV ON R.id = PV.record AND PV.element = '101'
WHERE R.id IN (SELECT record FROM xxx_facileforms_records WHERE record = R.id AND element = '4871')
GROUP BY PV.value
Does this looks right?
Thank You!
EDIT
Thank you for support and ideas! Yes, I left lot of un guessing. Sorry. Some input/output table data might help make it more clear.
_facileforms_form:
id | formname
---+---------
1 | myform
_facileforms_records:
id | form | submitted
----+------+--------------------
163 | 1 | 2014-06-12 14:18:00
164 | 1 | 2014-06-12 14:19:00
165 | 1 | 2014-06-12 14:20:00
_facileforms_subrecords:
id | record | element | title | name|type | value
-----+--------+---------+--------+-------------+--------
5821 | 163 | 101 | ticket | radio group | flight
5822 | 163 | 4871 | status | select list | canceled
5823 | 164 | 101 | ticket | radio group | flight
5824 | 165 | 101 | ticket | radio group | flight
5825 | 165 | 4871 | status | select list | canceled
Successful query result:
form_id | record_id | prim_val | count
1 | 163 | flight | 2
So i have to return value data (& sum those records) from those records where _subrecord element - 4871 is present (in this case 163 and 165).
And again Thank You!
Thank You for support and ideas! Yes i left lot of un guessing.. sorry . So may be some input/output table data might help.
_facileforms_form:
headers -> id | formname
1 | myform
_facileforms_records:
headers -> id | form | submitted
163 | 1 | 2014-06-12 14:18:00
164 | 1 | 2014-06-12 14:19:00
165 | 1 | 2014-06-12 14:20:00
_facileforms_subrecords
headers -> id | record | element | title | name | type | value
5821 | 163 | 101 | ticket | radio group| flight
5822 | 163 | 4871 | status | select list | canceled
5823 | 164 | 101 | ticket | radio group | flight
5824 | 165 | 101 | ticket | radio group | flight
5825 | 165 | 4871 | status | select list | canceled
Succesful Query result:
headers -> form_id | record_id | prim_val | count
1 | 163 | flight | 2
So i have to return value data (& sum those records) from those records where _subrecord element - 4871 is present (in this case 163 and 165).
And again Thank You!
No, it doesn't look quite right. There's a predicate "R.id IN (subquery)" but that subquery itself has a reference to R.id; it's a correlated subquery. Looks like something is doubled up there. (We're assuming here that id is a UNIQUE or PRIMARY key in each table.)
The subquery references an identifier element... the only other reference we see to that identifier is from the _subrecords table (we don't see any reference to that column in _records table... if there's no element column in _records, then that's a reference to the element column in PV, and that predicate in the subquery will never be true at the same time the PV.element='101' predicate is true.
Kudos for qualifying the column references with a table alias, that makes the query (and the EXPLAIN output) much easier to read; the reader doesn't need to go digging around in the table definitions to figure out which table does and doesn't contain which columns. But please take that pattern to the next step, and qualify all column references in the query, including column references in the subqueries.
Since the reference to element isn't qualified, we're left to guess whether the _records table contains a column named element.
If the goal is to return only the rows from R with element='4871', we could just do...
WHERE R.element='4871'
But, given that you've gone to the bother of using a subquery, I suspect that's not really what you want.
It's possible you're trying to return all rows from R for a _form, but only for the _form where there's at least one associated _record with element='4871'. We could get that result returned with either an IN (subquery) or an EXISTS (correlated_ subquery) predicate, or an anti-join pattern. I'd give examples of those query patterns; I could take some guesses at the specification, but I would only be guessing at what you actually want to return.
But I'm guessing that's not really what you want. I suspect that _records doesn't actually contain a column named element.
The query is already restricting the rows returned from PV with those that have element='101'.)
This is a case where some example data and the example output would help explain the actual specification; and that would be a basis for developing the required SQL.
FOLLOWUP
I'm just guessing... maybe what you want is something pretty simple. Maybe you want to return rows that have element value of either '101' or '4913'.
The IN comparison operator is a convenient of way of expressing the OR condition, that a column be equal to a value in a list:
SELECT F.id AS form_id
, R.id AS record_id
, PV.value AS prim_val
, COUNT(PV.value) AS count
FROM xxx_facileforms_forms F
JOIN xxx_facileforms_records R
ON R.form = F.id
JOIN xxx_facileforms_subrecords PV
ON PV.record = R.id
AND PV.element IN ('101','4193')
GROUP BY PV.value
NOTE: This query (like the OP query) is using a non-standard MySQL extension to GROUP BY, which allows non-aggregate expressions (e.g. bare columns) to be returned in the SELECT list.
The values returned for the non-aggregate expressions (in this case, F.id and R.id) will be a values from a row included in the "group". But because there can be multiple rows, and different values on those rows, it's not deterministic which of values will be returned. (Other databases would reject this statement, unless we wrapped those columns in an aggregate function, such as MIN() or MAX().)
FOLLOWUP
I noticed that you added information about the question into an answer... this information would better be added to the question as an EDIT, since it's not an answer to the question. I took the liberty of copying that, and reformatting.
The example makes it much more clear what you are trying to accomplish.
I think the easiest to understand is to use EXISTS predicate, to check whether a row meeting some criteria "exists" or not, and exclude rows where such a row does not exist. This will use a correlated subquery of the _subrecords table, to which check for the existence of a matching row:
SELECT f.id AS form_id
, r.id AS record_id
, pv.value AS prim_val
, COUNT(pv.value) AS count
FROM xxx_facileforms_forms f
JOIN xxx_facileforms_records r
ON r.form = f.id
JOIN xxx_facileforms_subrecords pv
ON pv.record = r.id
AND pv.element = '101'
-- only include rows where there's also a related 4193 subrecord
WHERE EXISTS ( SELECT 1
FROM xxx_facileforms_subrecords sx
WHERE sx.element = '4193'
AND sx.record = r.id
)
--
GROUP BY pv.value
(I'm thinking this is where OP was headed with the idea that a subquery was required.)
Given that there's a GROUP BY in the query, we could actually accomplish an equivalent result with a regular join operation, to a second reference to the _subrecords table.
A join operation is often more efficient than using an EXISTS predicate.
(Note that the existing GROUP BY clause will eliminate any "duplicates" that might otherwise be introduced by a JOIN operation, so this will return an equivalent result.)
SELECT f.id AS form_id
, r.id AS record_id
, pv.value AS prim_val
, COUNT(pv.value) AS count
FROM xxx_facileforms_forms f
JOIN xxx_facileforms_records r
ON r.form = f.id
JOIN xxx_facileforms_subrecords pv
ON pv.record = r.id
AND pv.element = '101'
-- only include rows where there's also a related 4193 subrecord
JOIN xxx_facileforms_subrecords sx
ON sx.record = r.id
AND sx.element = '4193'
--
GROUP BY pv.value

Complex Mysql string not returning row

i have 3 rows on "Services" table:
ID | name | ObrID
0 | A | 1
1 | B | 2
2 | C | -1
-1 is a none existing Obr, the service 2 doesn't contains any Obr or it was deleted.
if i fetch with select * from Services, it works as expected, but if i do my search sql:
select
*,
(select Name from Obrs where ID=ObrID) as ObrName
from
Services
where
(select Name from Obrs where ID=ObrID) like '%SEARCH_STRING%'
it doesn't return the last line. Is there any way so it return something like:
ID | name | ObrID | ObrName
0 | A | 1 | ObrA
1 | B | 2 | ObrB
3 | C | -1 | NULL
You want to use left join.
http://www.tizag.com/mysqlTutorial/mysqlleftjoin.php
SELECT s.*,o.ObrName from Services s
LEFT JOIN Obrs o ON ID=ObrID
WHERE OrbName LIKE '%$SEARCH_STRING%' OR OrbName IS NULL
or:
SELECT * FROM (select s.*,o.ObrName from Services s
LEFT JOIN Obrs o ON ID=ObrID) tmp
WHERE OrbName LIKE '%$SEARCH_STRING%' OR OrbName IS NULL
May be below can help:
select s.*,ob.Name from Services as s left join Obrs as ob on s.ID=ob.ObrID where ob.Name like '%$SEARCH_STRING%';
If there is no Obrs.Name because your ObrID is -1, then Obrs.Name will be NULL and therefor not LIKE '%$SEARCH_STRING%'. You can add an additional condition to also include these cases:
where
(select Name from Obrs where ID=ObrID) like '%$SEARCH_STRING%'
OR ObrID = -1
And follow Flöcsy's suggestion and use a LEFT JOIN. Joins are always the preferred method, especially vs. correlated subquerys. The working condition when using a LEFT JOIN is
WHERE
Obrs.Name LIKE '%$SEARCH_STRING%'
OR Obrs.Name IS NULL