Conditional insert query (Row count validation). (MYSQL) - mysql

I am trying to write a query that will count and compare the number of rows of two tables on two different databases. If they are equal then a record will be inserted into another table as 'Pass', else it will result in a 'Fail'.
I haven't been able to find any answers through google searches... Here is my query that isn't working:
select
case when
((select count(1) from db1.transaction) = (select count(1) from db2.transaction))
then
insert into db3.validation (test_result) values ('pass')
else
insert into db3.validation (test_result) values ('fail')
end;

You can do this by reversing the order. Do a single insert with a select choosing the value:
insert into db3.validation(test_result)
select (case when t1.cnt1 = t2.cnt2 then 'pass' else 'fail' end)
from (select count(1) as cnt1 from db1.transaction) t1 cross join
(select count(1) as cnt2 from db2.transaction) t2;
Note that I moved the subqueries from the case to a from clause, simply because I find them easier to read this way. You can keep them in the case if you prefer.

Related

How to run two different queries based on IF condition?

I have a scenario in which a table might exist in some databases. I need my query to run when the table exists and also when it doesn't. The below query when ran, gives an error Operand should contain 1 column(s). How can I make this query work without using a stored procedure? I need to use it with PySpark SQL.
SELECT IF(
EXISTS(
SELECT * FROM information_schema.TABLES WHERE TABLE_SCHEMA = 'dbdemo' AND TABLE_NAME = 'tier_report') > 0,
(SELECT a.*, b.tierchangedate, b.tierchangetype
FROM
(SELECT mobile, enrolledstorecode as storecode, tier as customertier, isprofileupdated, DATE(profileupdatedate) as profileupdatedate, modifiedenrolledon as enrolledon, referralcode, (CASE WHEN(countrycode IS NULL) THEN '91' ELSE countrycode END) as countrycode
FROM dbdemo.member_report) a
INNER JOIN
(SELECT mobile, DATE(tierchangedate) as tierchangedate, tierchangetype FROM dbdemo.tier_report) b
ON a.mobile=b.mobile),
(SELECT mobile, enrolledstorecode as storecode, tier as customertier, isprofileupdated, DATE(profileupdatedate) as profileupdatedate, modifiedenrolledon as enrolledon, referralcode, (CASE WHEN(countrycode IS NULL) THEN '91' ELSE countrycode END) as countrycode
FROM dbdemo.member_report));

SQL query to get percentages within a grouping

I've looked over similar questions and I just can't seem to get this right.
I have a table with three columns: ID, Date, and Method. None are unique.
I want to be able to see for any given date, how many rows match a certain pattern on Method.
So, for example, if the table has 100 rows, and 8 of them have the date "01-01-2020" and of those 8, two of them have a method of "A", I would want a return row that says "01-01-2020", "8", "2", and "25%".
My SQL is pretty rudimentary. I have been able to make a query to get me the count of each method by date:
select Date, count(*) from mytable WHERE Method="A" group by Date;
But I haven't been able to figure out how to put together the results that I am needing. Can someone help me out?
You could perform a count over a case expression for that method, and then divide the two counts:
SELECT date,
COUNT(*),
COUNT(CASE method WHEN 'A' THEN 1 END),
COUNT(CASE method WHEN 'A' THEN 1 END) / COUNT(*) * 100
FROM mytable
GROUP BY date
I'm assuming you're interested in all methods rather than just 'A', so you could do the following:
with ptotals as
(
SELECT
thedate,
count(*) as NumRows
FROM
mytable
group by
thedate
)
select
mytable.thedate,
mytable.themethod,
count(*) as method_count,
100 * count(*) / max(ptotals.NumRows) as Pct
from
mytable
inner join
ptotals
on
mytable.thedate = ptotals.thedate
group by
mytable.thedate,
mytable.themethod
You can use AVG() for the ratio/percentage:
SELECT date, COUNT(*),
SUM(CASE WHEN method = 'A' THEN 1 ELSE 0 END),
AVG(CASE WHEN method = 'A' THEN 100.0 ELSE 0 END)
FROM t
GROUP BY date;

insert select ignore some subquery returned values

I am trying to do an insert select but require some aliased values for calculations but don't need all of them for my insert. I just need field0, total_sum, hard_coded_val but rely on the others for the calculations.
is there any way to either ignore the other values or specify the VALUES() in the insert SELECT?
INSERT INTO table(field0,total_sum,hard_coded_val)
SELECT s.*, sum1+sum2 AS total_sum, 'hard_coded_val' FROM
(SELECT t.*, (fielda+fieldb)*2 AS sum1, (fieldc+fieldd)/4 AS sum2 from
(SELECT field0,
sum(IF(field1 = 1, totalcount,0)) AS fielda,
sum(IF(field1 = 2, totalcount,0)) AS fieldb,
sum(IF(field1 = 3, totalcount,0)) AS fieldc,
sum(IF(field1 = 4,totalcount,0)) AS fieldd
from source_table GROUP BY field0)
t ORDER BY sum1 DESC)
s ORDER BY total_sum DESC
You just need to limit the number of columns you're returning. * will return all columns for the table associated with it.
INSERT INTO table(field0,total_sum,hard_coded_val)
SELECT s.field0, sum1+sum2 AS total_sum, 'hard_coded_val' FROM
...

CASE Statement instead of inner join

This is my table structure:
CUST_ID ORDER_MONTH
---------------------
1 1
1 5
2 3
2 4
My objective is to tag these customers as either New or Returning customers.
When I filter the query lets say for month 1 then customer 1 should have the tag 'New' but when I filter it for month 5 then customer 1 should show up as 'Return' as he already made a purchase in month 1.
Same way customer ID 2 should show up as New for month 3 and return for month 4.
I want to do this using a CASE statement and not inner join.
Thanks
If you insist on using a case statement, the logic would be something like "If this is the first month for that user, write new, otherwise write returning." The query would be as follows:
SELECT CASE
WHEN m.month = (SELECT MIN(month) FROM myTable WHERE customer = m.customer) THEN 'New'
ELSE 'Returning' END AS customerType
FROM myTable m;
However, I think this would be nicer and more readable in a JOIN. You can write an aggregation query to get the earliest month for each user, and then use COALESCE() to replace null values with 'Returning'. The aggregation:
SELECT customer, MIN(month) AS minMonth, 'New' AS customerType
FROM myTable
GROUP BY customer ;
To get the rest:
SELECT m.customer, m.month, COALESCE(t.customerType, 'Returning') AS customerType
FROM myTable m
LEFT JOIN(
SELECT customer, MIN(month) AS minMonth, 'New' AS customerType
FROM myTable
GROUP BY customer) t ON t.customer = m.customer AND t.minMonth = m.month;
Here is an SQL Fiddle example that shows both examples.
You don't need a JOIN and a case statement would probably be overkill...
SELECT CUST_ID, IF(COUNT(1)>1, 'Returning', 'New') AS blah
FROM the_table
WHERE ORDER_MONTH <= the_month
GROUP BY CUST_ID
;
Of course, using just month is going to cause problems after a year (or really, after passing December.)
This would be better
SELECT CUST_ID, IF(COUNT(1)>1, 'Returning', 'New') AS blah
FROM the_table
WHERE order_date <= some_date
GROUP BY CUST_ID
;
Well I do not reccomend this way but this is what you want.
select *
,case when order_month = (select MIN(order_month) from #temp t2 where t1.cust_ID =t2.cust_id) THEN 'NEW' ELSE 'Return' end 'Type'
from #temp t1
I think I get what you're trying to do. Your case statement basically just needs to check if the customer's month equals the month you're filtering by. Something like this:
SELECT
<your other fields>,
CASE WHEN Order_Month = <your filter> THEN 'New'
ELSE 'Return'
END AS 'SomeName'
FROM <your table>
Try this query
select a.CUST_ID, a.ORDER_MONTH ,case when b is not null then 'Return' else 'New' end as type
from tablename a
join tablename b on a.CUST_ID=b.CUST_ID and a.ORDER_MONTH>b.ORDER_MONTH
SELECT *,
CASE
WHEN EXISTS (SELECT *
FROM [YourTable] t2
WHERE t1.cust_id = t2.cust_id
AND t2.order_month < t1.order_month) THEN 'Return'
ELSE 'New'
END
FROM [YourTable] t1
This query uses CASE on an EXISTS clause.
The EXISTS is on a subquery which queries the same table for any rows in previous months.
If there are rows for previous months then the EXISTS is true and the CASE returns 'Return'. If there are no rows for previous months then the EXISTS is false and the CASE returns 'New'.

multiple select on stored procedure

I'm trying to do multiple selects from one table but it only shown the last select statement.
CREATE PROCEDURE `usp_GetStockCard` (IN Matecode varchar(10))
BEGIN
(select tran_date as tran_date
from TM_matbalance
where Mate_code=Matecode);
(select Mate_code as Mate_code
from TM_matbalance
where Mate_code=Matecode);
(select tran_qtyx as Qty_in
from TM_matbalance
where tran_type='IN'
and mate_code=matecode);
(select tran_qtyx as Qty_out
from TM_matbalance
where tran_type='OUT'
and mate_code=matecode);
END
I've tried to change semicolon to comma after each select statement but it said that syntax error: missing 'semicolon'.
please help.
I look at your problem and I think I solve it.
Basically there is two problems here first one is to pivot your table where your Tran_Qtyx column become Qty_In and Qty_Out based on value in Tran_Type column (IN or OUT)... That part of problem you solve with this query
SELECT Tran_Date, Mate_Code,
SUM(CASE WHEN Tran_Type = 'IN' THEN Tran_Qtyx ELSE 0 END) Qty_In,
SUM(CASE WHEN Tran_Type = 'OUT' THEN Tran_Qtyx ELSE 0 END) Qty_Out
FROM myTable
WHERE Mate_Code = 'MAT001'
GROUP BY DATE(Tran_Date)
NOTE: In your desired result I only see 'MAT001'as Mate_Code so I stick with that in this solution and exclude MAT002 from result.
More about pivot table you can read here, there you can find a link, which is good to take a look, and where you can find a lot of stuff about mysql query's.
The second part of your problem is to get Qty_Balance column. Similar problem is solved here. It's how to calculate row value based on the value in previous row.
So your complete query could look like this:
SELECT t1.Tran_Date, t1.Mate_Code, t1.Qty_In, t1.Qty_Out,
#b := #b + t1.Qty_In - t1.Qty_Out AS Qty_Balance
FROM
(SELECT #b := 0) AS dummy
CROSS JOIN
(SELECT Tran_Date, Mate_Code,
SUM(CASE WHEN Tran_Type = 'IN' THEN Tran_Qtyx ELSE 0 END) Qty_In,
SUM(CASE WHEN Tran_Type = 'OUT' THEN Tran_Qtyx ELSE 0 END) Qty_Out
FROM myTable
WHERE Mate_Code = 'MAT001'
GROUP BY DATE(Tran_Date)) AS t1
ORDER BY t1.Tran_Date;
NOTE: probably only think you should change here is table name and it's should work.
Here is SQL Fiddle so you can see how that's work!
GL!
You will need to structure your query into one, or pass in a parameter to the stored procedure to select which output/query you want, to restructure your query you will need something like:
`CREATE PROCEDURE `usp_GetStockCard` (IN Matecode varchar(10))
BEGIN
(select tran_date as tran_date, Mate_code as Mate_code, tran_qtyx as Qty
from TM_matbalance
where Mate_code=Matecode
and (tran_type='IN' or tran_type='OUT');
END`
Or try this if you have an ID column:
SELECT coalesce(ta.id, tb.id) as tran_id, coalesce(ta.tran_date, tb.tran_date) as tran_date, coalesce(ta.Mate_code, tb.Mate_code) as Mate_code, ta.tran_type as Qty_In, tb.tran_type as Qty_Out
from (select ta.*
from TM_matbalance ta
where ta.tran_type = 'IN'
and Mate_code=Matecode
) ta full outer join
(select tb.*
from TM_matbalance tb
where tb.tran_type = 'OUT'
and Mate_code=Matecode
) tb
on ta.id = tb.id ;
just replace "id" with the name of your ID column if you don't need to return the id column then remove coalesce(ta.id, tb.id) as tran_id