Grouping different column into one row - mysql

How to make one row in different rows and column
SELECT
internal_id, store_id, user_id, shift_info,
DATE(log_datetime) dates,
(case when log_action = '0' then TIME(log_datetime) end) as time_in,
(case when log_action = '0' then CONCAT(log_lat, ",", log_lng) end) as loc_in,
(case when log_action = '1' then TIME(log_datetime) end) as time_out,
(case when log_action = '1' then CONCAT(log_lat, ",", log_lng) end) as loc_out
FROM
attendance_store_user
WHERE
user_id = "A4CBD64F-D21C-5612-CCF5-497892B62E76"
i want result like this :

You could try using a join of the same table filter for null time_out and time_in
select a.dates, a.store_id, a,time_in, b.time_out
FROM attendance_store_user a
INNER JOIN attendance_store_user b on a.dates = b.dates
and a.user_id = b.user_id
and a.time_out is null
and b.time_in is null
WHERE a.user_id = "A4CBD64F-D21C-5612-CCF5-497892B62E76"

Related

Can you join a table with another table you are pivoting on a field you are creating with the pivot?

I have a table I need to pivot that contains a value I need to join with a field in another table. I'm trying to determine if I can do this in one step, or if I need to pivot the first table and then join them together. GROUP_ID is in field_name in the redcap_data table and needs to be joined with group_id in redcap_data_access_groups.
CREATE VIEW vwGlobalHealthInfants AS
SELECT rd.record as record_id,
MAX(CASE WHEN rd.field_name = '__GROUP_ID__' THEN rd.value ELSE NULL END) as GroupId,
g.group_name as hospno,
MAX(CASE WHEN rd.field_name = 'admission_temperature' THEN rd.value ELSE NULL END) as adtemp,
MAX(CASE WHEN rd.field_name = 'antenatal_care' THEN rd.value ELSE NULL END) as antecare,
MAX(CASE WHEN rd.field_name = 'anti_hypertensive' THEN rd.value ELSE NULL END) as antihyper,
MAX(CASE WHEN rd.field_name = 'anticonvulsants' THEN rd.value ELSE NULL END) as anticonvul
FROM (
redcapVON.redcap_data rd
JOIN redcapVON.redcap_data_access_groups g ON ( (
GroupId = g.group_id
) )
)
WHERE (
rd.project_id = 12
)
GROUP BY rd.record
I don't know if it's possible to get it to recognize the GroupID field in the join before the pivot.
CTE would solve it. We just don't have the most updated version of mysql to run it. 2 steps it is.

Update table if all results from multiple UNION queries is 0

I have 2 tables with stock from two different sellers.
If I can not source the product from any of these two sellers then I would like to set a value in another table to '0'.
First of all I am getting some required values from the two seller stock tables combined with a UNION
(SELECT A.`id`, B.`product_id`, A.`internal_id`, CASE WHEN A.`in_stock` = 'Stock available' THEN '1' ELSE '0' END as `in_stock` FROM `pricing_dm` A LEFT JOIN `pricing_vendor_mapping` B ON A.`internal_id`= B.`internal_id` WHERE B.`vendor_id` = '1' AND B.`product_id` > '0'
UNION
SELECT A.`id`, B.`product_id`, A.`internal_id`, CASE WHEN A.`in_stock` = 'In Stock' THEN '1' ELSE '0' END as `in_stock` FROM `pricing_m` A LEFT JOIN `pricing_vendor_mapping` B ON A.`internal_id`= B.`internal_id` WHERE B.`vendor_id` = '2' AND B.`product_id` > '0') t1
If I get a result like below where in_stock = 0 for both sellers then I would like to update another field with 0
id product_id internal_id in_stock
1 123 5555 0
1 123 4567 0
If I can source the product from one (like below) or both sellers then I don't want to do anything.
id product_id internal_id in_stock
1 123 5555 0
1 123 4567 1
Basically how can I check if all results for a product_id are 'in_stock = 0' and based on that do an update of another table.
Thank you
There are easier ways to do this if the tables can be joined, but You could get the max in_stock number and knowing that if it's over 0 you could do it with a CTE like this (I am not able to test this in mysql so it may need some syntax correction)
WITH CTE (in_stock) AS (
SELECT MAX(in_stock) from (
(SELECT A.`id`, B.`product_id`, A.`internal_id`, CASE WHEN A.`in_stock` = 'Stock available' THEN '1' ELSE '0' END as `in_stock` FROM `pricing_dm` A LEFT JOIN `pricing_vendor_mapping` B ON A.`internal_id`= B.`internal_id` WHERE B.`vendor_id` = '1' AND B.`product_id` > '0'
UNION
SELECT A.`id`, B.`product_id`, A.`internal_id`, CASE WHEN A.`in_stock` = 'In Stock' THEN '1' ELSE '0' END as `in_stock` FROM `pricing_m` A LEFT JOIN `pricing_vendor_mapping` B ON A.`internal_id`= B.`internal_id` WHERE B.`vendor_id` = '2' AND B.`product_id` > '0') t1 ))
UPDATE some_table SET some_column = 0
where CTE.in_stock < 1
I used nested queries and a variable to meet your criteria.
See example DDL in this link:https://www.db-fiddle.com/f/8jUMnbEFpGWA4fmmP67yw9/0 I think this meets your requirements.
Here is my Query, with comments:
#check initial another table values
select * from another_table;
#check the given resultset
#there are 3 pairs,
#2 of which meet the condition for not updating
#1 of the pairs meets the condition for doing the requested update
SELECT A.`id`, B.`product_id`, A.`internal_id`, CASE WHEN A.`in_stock` = 'Stock available' THEN '1' ELSE '0' END as `in_stock` FROM `pricing_dm` A LEFT JOIN `pricing_vendor_mapping` B ON A.`internal_id`= B.`internal_id` WHERE B.`vendor_id` = '1' AND B.`product_id` > '0'
UNION
SELECT A.`id`, B.`product_id`, A.`internal_id`, CASE WHEN A.`in_stock` = 'In Stock' THEN '1' ELSE '0' END as `in_stock` FROM `pricing_m` A LEFT JOIN `pricing_vendor_mapping` B ON A.`internal_id`= B.`internal_id` WHERE B.`vendor_id` = '2' AND B.`product_id` > '0';
#the requested update statement
set #chk1 := 0;
update another_table
set crab_people = 0
where product_id in
#this nested query will return all product_id
#that fits the criteria to update another_table
(select product_id_not_in_stock from
(select
case
when product_id = #chk1 and in_stock = 0 then #chk1
when product_id != #chk1 and in_stock = 0 then #chk1 := product_id
end as product_id_not_in_stock
from
(SELECT A.`id`, B.`product_id`, A.`internal_id`, CASE WHEN A.`in_stock` = 'Stock available' THEN '1' ELSE '0' END as `in_stock` FROM `pricing_dm` A LEFT JOIN `pricing_vendor_mapping` B ON A.`internal_id`= B.`internal_id` WHERE B.`vendor_id` = '1' AND B.`product_id` > '0'
UNION
SELECT A.`id`, B.`product_id`, A.`internal_id`, CASE WHEN A.`in_stock` = 'In Stock' THEN '1' ELSE '0' END as `in_stock` FROM `pricing_m` A LEFT JOIN `pricing_vendor_mapping` B ON A.`internal_id`= B.`internal_id` WHERE B.`vendor_id` = '2' AND B.`product_id` > '0') as t1
order by product_id, in_stock DESC, internal_id) as t2
where product_id_not_in_stock is not null
group by product_id_not_in_stock
having count(product_id_not_in_stock) > 1);
#confirm the changes went though
#expect crab_people from another_table to be updated
#where the product id is not in stock from both tables: pricing_dm and pricing_m
select * from another_table;

My two queries work separately but when I nest one inside of the other it no longer works

My first query is:
SELECT
SUM(CASE WHEN (Transactions.RegFunction = '1' AND Transactions.RegYear = "2017") THEN RegAmt END) AS GroupCurrsumFee,
SUM(CASE WHEN (Transactions.RegFunction = '1' AND Transactions.RegYear = "2017") THEN Transactions.LMSCAmt END) AS IndCurrsumFee
FROM AllTransactions
My second query is:
SELECT GroupAmt
FROM GroupFees
WHERE
'2016-11-01' BETWEEN BeginDate AND EndDate
AND RegYear = "2016"
AND GROUPID = "14"
AND RegFunction = 1;
When I run that query it returns the below:
| GroupAmt |
| 5.00 |
When I nest the second query inside of the first so that it can return that data in a column alias it does not show up. I have the two queries combined and written as the below:
SELECT
SUM(CASE WHEN (Transactions.RegFunction = '1' AND Transactions.RegYear = "2017") THEN RegAmt END) AS GroupCurrsumFee,
SUM(CASE WHEN (Transactions.RegFunction = '1' AND Transactions.RegYear = "2017") THEN Transactions.LMSCAmt END) AS IndCurrsumFee,
(SELECT GroupAmt FROM GroupFees
WHERE
'2016-11-01' BETWEEN BeginDate AND EndDate
AND RegYear = "2016"
AND GROUPID = "14"
AND RegFunction = 1) AS GroupFee
FROM AllTransactions
Use a join instead. Given the possibility that query might return NULL I suggest a left join with join condition that is always true. (Yes a bit "hacky".) Note, there is no guarantee that subquery returns just one row. If it does your overall result may not be what you are expecting.
SELECT SUM(CASE
WHEN (
Transactions.RegFunction = '1'
AND Transactions.RegYear = "2017"
)
THEN RegAmt
END) AS GroupCurrsumFee
, SUM(CASE
WHEN (
Transactions.RegFunction = '1'
AND Transactions.RegYear = "2017"
)
THEN Transactions.LMSCAmt
END) AS IndCurrsumFee
, GroupFee.GroupAmt
FROM AllTransactions
LEFT JOIN (
SELECT GroupAmt
FROM GroupFees
WHERE '2016-11-01' BETWEEN BeginDate
AND EndDate
AND RegYear = '2016'
AND GROUPID = '14'
AND RegFunction = 1
) AS GroupFee on 1=1

SQL Select if else

I need some help.. I need to output the value of DisplayName if the value of fullname return a null or empty as FullName.
something like
if(u.first_name && u.last_name are not empty)
output CONCAT(u.first_name,' ',u.last_name)
else
output max(case when t.field_id = 1 then t.value else '' end)
but how? also my query took 3.45 seconds :(..
SELECT * FROM(
SELECT
t.user_id,
##this code
max(case when t.field_id = 1 then t.value else '' end) DisplayName,
CONCAT(u.first_name,' ',u.last_name) FullName,
max(case when t.field_id = 270 then t.value else '' end) Gender,
max(case when t.field_id = 274 then t.value else '' end) Birthday,
max(case when t.field_id = 274 then FLOOR(DATEDIFF(CURRENT_DATE, STR_TO_DATE(t.value,'%m/%d/%Y'))/365) else '' end) Age,
max(case when t.field_id = 275 then t.value else '' end) Phone,
max(case when t.field_id = 286 then t.value else '' end) Email,
max(case when t.field_id = 71 then t.value else '' end) Occupation,
max(case when t.field_id = 73 then t.value else '' end) CurrentCountry,
max(case when t.field_id = 24 then t.value else '' end) Region,
max(case when t.field_id = 355 then t.value else '' end) Province,
max(case when t.field_id = 354 then t.value else '' end) City
FROM wp_bp_xprofile_data t
LEFT JOIN (
SELECT
user_id id,
max(case when meta_key = 'first_name' then meta_value end) first_name,
max(case when meta_key = 'last_name' then meta_value end) last_name
from wp_usermeta
GRoup by user_id
)as u
ON u.id = t.user_id
GROUP BY user_id
)temp
WHERE 1 = 1
##Some Condition to be added
LIMIT 0 , 30
I would change to a multiple join to same table repeatedly to get each field on its own criteria
as a possibility of performance. Start the profile data one for say the field_id = 1 as the basis,
then join all the rest on that same key, then no grouping by or max/case when on every tested row.
IF some fields may NOT exists, just have as LEFT-JOIN to the re-used table with alternate alias.
I would ensure you have a compound/covering index on your profile table with the following key
( user_id, field_id, value )
Then do the following query. The interesting thing here, is it basically opens the same table for each "component" part of the user_ID and gets them all lined up, but runs the query based only on a single instance of records associated with field_id = 1 in the where clause. All the other instances are in their respective aliases joined ON clause. So now, I just run through the records for field_id = 1, and if found on the other tables, grabs the value, otherwise blank (via coalesce). Similarly joined to the user meta-data table to get the first/last name parts.
if this works for you, I would be interested in knowing the performance one-way or the other. The benefit is that it doesn't have to query EVERYONE up front (the inner-most query) to then run the main query of all records, apply the group by, then stop at your 30 limit clause. It just gets up to the first 30 where field_id = 1 and its done. Now, if the population of "field_id = 1" is a low populated field, and you want to swap with another, so be it, you know your data better than us.
SELECT
DN.User_ID,
case when fn.user_id is null and ln.user_id is null then DN.value
when fn.user_id is null then ln.meta_value
when ln.user_id is null then fn.meta_value
else concat( fn.meta_value, ' ', ln.meta_value ) end as FinalName,
DN.Value DisplayName,
CONCAT( COALESCE( fn.meta_value, '' ),' ',COALESCE( ln.meta_value, '' )) FullName,
COALESCE( G.Value, '' ) Gender,
COALESCE( BD.Value, '' ) Birthday,
COALESCE( FLOOR( DATEDIFF( CURRENT_DATE, STR_TO_DATE( BD.value,'%m/%d/%Y'))/365), '' ) Age,
COALESCE( P.Value, '' ) Phone,
COALESCE( E.Value, '' ) Email,
COALESCE( O.Value, '' ) Occupation,
COALESCE( CC.Value, '' ) CurrentCountry,
COALESCE( R.Value, '' ) Region,
COALESCE( PR.Value, '' ) Province,
COALESCE( C.Value, '' ) City
from
wp_bp_xprofile_data DN
LEFT JOIN wp_bp_xprofile_data G
ON DN.User_ID = G.User_ID AND G.field_id = 270
LEFT JOIN wp_bp_xprofile_data BD
ON DN.User_ID = BD.User_ID AND BD.field_id = 274
LEFT JOIN wp_bp_xprofile_data P
ON DN.User_ID = P.User_ID AND P.field_id = 275
LEFT JOIN wp_bp_xprofile_data E
ON DN.User_ID = E.User_ID AND E.field_id = 286
LEFT JOIN wp_bp_xprofile_data O
ON DN.User_ID = O.User_ID AND O.field_id = 71
LEFT JOIN wp_bp_xprofile_data CC
ON DN.User_ID = CC.User_ID AND CC.field_id = 73
LEFT JOIN wp_bp_xprofile_data R
ON DN.User_ID = R.User_ID AND R.field_id = 24
LEFT JOIN wp_bp_xprofile_data PR
ON DN.User_ID = PR.User_ID AND PR.field_id = 355
LEFT JOIN wp_bp_xprofile_data C
ON DN.User_ID = C.User_ID AND C.field_id = 354
LEFT JOIN wp_usermeta FN
ON DN.User_ID = FN.User_ID AND FN.meta_key = 'first_name'
LEFT JOIN wp_usermeta LN
ON DN.User_ID = LN.User_ID AND LN.meta_key = 'last_name'
where
DN.field_id = 1
AND O.Value like '%Programmer%'
LIMIT
0, 30
I modified to add a FINAL Name by use of a case/when.
if both the alias FN/LN (first name / last name) are BOTH null, then get the DN (display name) value. Otherwise we have AT LEAST ONE or BOTH parts of the first/last name field. If the first name was null, just return the last name. If the last name was null, return the first name, otherwise BOTH first and last names were available, and return the concatinated version of the name.
As for applying extra WHERE clauses. As soon as you add a "required" criteria to the where clause against any of the left-join aliases, it will in-effect turn them into INNER JOINs and only include those that HAVE that component AND that component has the value you want... So, per your comment I would just add...
where
DN.field_id = 1
AND BD.User_ID IS NOT NULL
AND STR_TO_DATE( BD.value,'%m/%d/%Y') BETWEEN '2009-01-01' and '2012-01-01'
You could use your datediff for age and do that between 1 and 2, but just a preference to pick a date range of interest..
For your additional comment about Programmer filtering, the way you had it was trying to test ALL the joined aliases looking for programmer, but at the same time, all of them required because you wanted them all as NOT NULL. If you want a field required, but no other specific criteria, such as ALWAYS must have email address, then just change
LEFT JOIN wp_bp_xprofile_data E
to
JOIN wp_bp_xprofile_data E
if you want to make sure the field is considered only if it has a value other than space (such as your last/first name)
LEFT JOIN wp_usermeta FN
ON DN.User_ID = FN.User_ID
AND FN.meta_key = 'first_name'
AND LENGTH( TRIM( COALESCE( FN.meta_Value, '' ))) > 0
This will make sure the record is only considered when it actually has a non-empty string value.
Back to your consideration of "%Programmer%'... why would you ever expect a city, Province, region, etc to have a value of programmer. You should only require the Occupation instance to have the value. Also, because you had an OR, it was doing ALL the rows. You would need to have wrapped the conditions something like
where
DN.field_id = 1
AND ( O.Value like '%Programmer%'
OR E.Value like '%#gmail.com'
OR C.Value like 'Some City' )
Notice I wrapped my ADDITIONAL criteria OR components. This way it still only starts with the Field_ID = 1 entries, but based on the JOIN adds the extra criteria, and in this case, DN.field_id = 1 always, but ANY ONE (or more) of the OR conditions must also be true... The Occupation alias has a value like programmer, email alias has a value of gmail, the city alias like 'Some City'.
Hopefully this clarifies how to implement... Also, make note, that using any LIKE qualifier that has '%' leading the string needs to compare through the whole string and will slow the query down some, but since the join is based on the user ID and the field_ID value, that should still keep it fast (relatively).
Try this:
SELECT if( trim(CONCAT(first_name,' ', lastName))='',
DisplayName,
CONCAT(first_name,' ', lastName) ) as Name
...rest of the fieds on TA subquery
FROM (
(SELECT
t.user_id,
max(case when t.field_id = 1 then t.value else '' end) DisplayName,
max(case when t.field_id = 270 then t.value else '' end) Gender,
max(case when t.field_id = 274 then t.value else '' end) Birthday,
max(case when t.field_id = 274
then FLOOR( DATEDIFF( CURRENT_DATE,
STR_TO_DATE( t.value, '%m/%d/%Y')) / 365)
else '' end) Age,
max(case when t.field_id = 275 then t.value else '' end) Phone,
max(case when t.field_id = 286 then t.value else '' end) Email,
max(case when t.field_id = 71 then t.value else '' end) Occupation,
max(case when t.field_id = 73 then t.value else '' end) CurrentCountry,
max(case when t.field_id = 24 then t.value else '' end) Region,
max(case when t.field_id = 355 then t.value else '' end) Province,
max(case when t.field_id = 354 then t.value else '' end) City
FROM wp_bp_xprofile_data t
GROUP BY user_id
) TA
LEFT JOIN
( SELECT user_id id,
max(case when meta_key = 'first_name'
then meta_value end) first_name,
max(case when meta_key = 'last_name'
then meta_value end) last_name
from wp_usermeta
GRoup by user_id ) as U on (ta.user_id = U.id)
)temp
WHERE 1 = 1
##Some Condition to be added
LIMIT 0 , 30

How can I sum two or more COUNT values in MySQL query?

I want to sump up two or more counted values [pivoting]
My query is as following:
SELECT
client_name.client_name ,
escort ,
count(case mission_status_reason when '4' then mission_status_reason end) as awaiting_upload_at_origin,
count(case mission_status_reason when '6' then mission_status_reason end) as awaiting_military_escort,
count(case mission_status_reason when '3' then mission_status_reason end) as enrouted_to_destination,
count(case mission_status_reason when '9' then mission_status_reason end) as awaiting_download,
( awaiting_military_escort +enrouted_to_destination+ awaiting_download ) as TOTAL
FROM usc_tmr
LEFT JOIN client_name on client_name.id = usc_tmr.client_name
WHERE escort='usg'
and mission_status_ops IN ('1','4','5','6')
GROUP BY client_name
My problem is calculating the TOTAL. Can you guys please help.
SELECT client_name.client_name,
escort,
SUM(mission_status_reason = 4) AS awaiting_upload_at_origin,
SUM(mission_status_reason = 6) AS awaiting_military_escort,
SUM(mission_status_reason = 3) AS enrouted_to_destination,
SUM(mission_status_reason = 9) AS awaiting_download,
SUM(mission_status_reason IN (3,6,9)) AS TOTAL
FROM usc_tmr LEFT JOIN client_name ON client_name.id = usc_tmr.client_name
WHERE escort = 'usg' AND mission_status_ops IN (1,4,5,6)
GROUP BY client_name