Mysql union select error - mysql

I am trying to display all records from table1 even if the catid not existing in table2 (all employee in table2 should have all catid from table1 with 0 days if not exising in table2) with the following sql query but getting an error
Error Code: 1054. Unknown column 'catid' in 'group statement'
select empid,days from table2 union select catid from
table1 group by empid, catid;
table1:
catid
1
2
3
table2:
empid catid days (computed column count(*))
1000 1 8
1000 3 10
expected result:
empid catid days
1000 1 8
1000 2 0 <---catid 2 and days 0 if catid not existing in table2 for empid 1000
1000 3 10

That is not the function of the union statement. Union statement does a set like capability which merging two sets. What you are looking for a is a join with the table 1 where you do a count and group by catid. Your data model to achieve this output itself is grievously wrong ;)
select employeeid, catid, sum(days) from table1, table2 group by employeeid, catid;

You just need a LEFT JOIN:
Select tab2.empid, tab2.catid, ifnull(tab2.days, 0)
from tab2
left join tab1 on tab2.catid = tab1.catid
Please note : While doing a UNION the number and type of the columns present in the first select should be the same as the next Selects.
So you need to first make the select columns in sync first.

can you check this and add empid similarly.
SELECT TABLE1.CATID, IFNULL(TABLE2.DAYS,0) FROM table1 LEFT OUTER JOIN
table2 ON table1.catid = table2.catid

Please use LEFT JOIN with IFNULL.
Select table2.empid, table1.catid, IFNULL(table2.days, 0) from table2
LEFT JOIN table1 ON table2.catid = table1.catid;

Related

select only when different value

I have this column: name and price. I don't really know how or why in mysql database there are few line that are double record exactly from the previous line.
how to select all records but show only one of the records if the record is double with a line in front or behind it?
For example I have this records:
id
name
price
1
book
5
2
lamp
7
3
lamp
7
4
book
5
5
book
5
the result I want is:
id
name
price
1
book
5
2
lamp
7
4
book
5
If you want to exclude rows that match the previous name, there are several ways like the following.
Case 1:
If you use MySQL8, you can use the LAG function.
SELECT t1.id,t1.name,t1.price FROM (
SELECT t2.id,t2.name,t2.price,
LAG(t2.name) OVER(ORDER BY t2.id) prev
FROM mytable t2
) t1
WHERE t1.prev IS NULL OR t1.name<>t1.prev
ORDER BY 1
Case 2:
If the ids are continuous without any steps, you will get the expected result by comparing name and the previous id by JOIN.
SELECT t1.id,t1.name,t1.price FROM mytable t1
LEFT JOIN mytable t2
ON t1.name=t2.name AND
t1.id=t2.id-1
WHERE t1.id=1 OR t2.id IS NOT NULL
ORDER BY 1
Case 3:
If the ids are not continuous, there is a way to get the maximum id that does not exceed the other id.
SELECT t1.id,t1.name,t1.price FROM mytable t1
LEFT JOIN mytable t2
ON t1.name=t2.name AND
t1.id=(SELECT MAX(t3.id) FROM mytable t3 WHERE t3.id<t2.id)
WHERE t1.id=1 OR t2.id IS NOT NULL
ORDER BY 1
DB Fiddle
Select distinct is not an option here as id column is always unique. I guess this will work for you:
select min(id), name, price from table_name group by name, price

MySql: How to select rows where all values are the same?

I have a table like this:
name |id | state
name1 12 4
name1 12 4
name2 33 3
name2 33 4
...
I want to select every name and id from table where state is only 4, that means name1 is correct, because it only has two records with state 4 and nothing more. Meanwhile name2 is wrong, because it has record with state 4 and record with state 3.
You can use aggregation as shown below:
SELECT name, id
FROM your_table
GROUP BY name, id
HAVING SUM(state<>4)=0;
See a Demo on SQL Fiddle.
select name, id from mytable where id not in
(select distinct id from mytable where state <> 4)
you might need 2 sub queries .
select with group by name were state 4
select with group by name
compare the count if the count is same then select it
example : select name , count (name) from table where state = 4 as T1
select name , count (name) from table as T2
select T1.name from T1 and T2 where T2.count = T1.count
You can use not exists like this:
select distinct name, id
from table1 a
where not exists (select *
from table1 b
where a.id=b.id and state<>4)
In a more general case you can use count distinct (with not exists or with a join):
select distinct name, id
from table1 a
where not exists (
select *
from table1 b
where a.id=b.id
group by id
HAVING count(distinct state)>1)

Count unique value in subquery without group

I would like to make a column which counts the occurrences of unique strings from a column within a subquery. However, I do not want to group the results. I need all of my original rows. I saw other posts where the count was selected in the following manner. I get error code 1146 because table_1 does not exist in my database, but is from a subquery. Does anyone know another way to do this?
SELECT table_1.columnA
,table_1.columnB
,table_2.CountB
,
FROM (
SELECT sometable.stuff AS 'columnA'
,sometable.morestuff AS 'columnB'
FROM sometable
WHERE blah_blah_blah = blah
) table_1
,(
SELECT columnB
,count(columnB) AS 'CountB'
FROM table_1
) table_2
WHERE table_1.columnB = table_2.columnB
Example of desired output:
columnA columnB CountB
1 Red 3
2 Green 2
3 Blue 1
4 Green 2
5 Red 3
6 Red 3
The subquery needs to count by columnB and join back to the original table:
select a.*, b.c
from table_1 a
join (
select columnB, count(*) c
from table_1
group by columnB) b on a.columnB = b.columnB;

SQL - How to use COUNT() with more than one table

I have a table that includes an COUNT() function that returns all the fields and counts them out. Now, I need to join another table and return both the number of rows that match and the rows that do no match. I am not exactly sure how I can use the GROUP BY and COUNT() function and get the results I need.
SELECT tb1.type, count(tb1.type) as total
FROM table1 tb1
GROUP BY tb1.type
That will return the totals for me:
RESULTS for TABLE1:
Type total
Egg 200
Cream 133
Milk 12
That's great. However, now I have another table...table 2 that has some records that match so doing that same query on that table will show something like:
RESULTS for TABLE2:
Type total
Egg 187
Cream 103
Milk 6
So, my results will need to look like this:
RESULTS for TABLE1:
Type total totalINTABLE2 totalNOTINTABLE2
Egg 200 187 13
Cream 133 103 30
Milk 12 6 6
Not sure if joining is best here, or a UNION, or EXISTS. What's getting me confused is the group by.
Well, you can simply JOIN both the resultset like
SELECT tb1.type,
tb1.total,
tb2.totalINTABLE2,
(tb1.total - tb2.totalINTABLE2) as totalNOTINTABLE2
FROM (
SELECT type, count(type) as total
FROM table1
GROUP BY type) tb1
JOIN (
SELECT type, count(type) as totalINTABLE2
FROM table2
GROUP BY type) tb2 ON tb1.type = tb2.type;
Use a CTE to calculate the total in each table then join them together:
;WITH
cte1 as (
SELECT tb1.type, count(tb1.type) as total
FROM table1 tb1
GROUP BY tb1.type
),
cte2 as (
SELECT tb2.type, count(tb2.type) as total
FROM table2 tb2
GROUP BY tb2.type
)
SELECT ISNULL(cte1.type, cte2.type) as type,
cte1.total as TotalInTable1,
cte2.total as TotalInTable2,
ISNULL(cte1.total, 0) - ISNULL(cte2.total, 0) as TotalNotInTable2
FROM cte1
FULL JOIN cte2 ON cte1.type = cte2.type

Using SUM() without grouping the results

I already read (this), but couldn't figure out a way to implement it to my specific problem. I know SUM() is an aggregate function and it doesn't make sense not to use it as such, but in this specific case, I have to SUM() all of the results while maintaining every single row.
Here's the table:
--ID-- --amount--
1 23
2 11
3 8
4 7
I need to SUM() the amount, but keep every record, so the output should be like:
--ID-- --amount--
1 49
2 49
3 49
4 49
I had this query, but it only sums each row, not all results together:
SELECT
a.id,
SUM(b.amount)
FROM table1 as a
JOIN table1 as b ON a.id = b.id
GROUP BY id
Without the SUM() it would only return one single row, but I need to maintain all ID's...
Note: Yes this is a pretty basic example and I could use php to do this here,but obviously the table is bigger and has more rows and columns, but that's not the point.
SELECT a.id, b.amount
FROM table1 a
CROSS JOIN
(
SELECT SUM(amount) amount FROM table1
) b
You need to perform a cartesian join of the value of the sum of every row in the table to each id. Since there is only one result of the subselect (49), it basically just gets tacked onto each id.
With MS SQL you can use OVER()
select id, SUM(amount) OVER()
from table1;
select id, SUM(amount) OVER()
from (
select 1 as id, 23 as amount
union all
select 2 as id, 11 as amount
union all
select 3 as id, 8 as amount
union all
select 4 as id, 7 as amount
) A
--- OVER PARTITION ID
PARTITION BY which is very useful when you want to do SUM() per MONTH for example or do quarterly reports sales or yearly...
(Note needs distinct it is doing for all rows)
select distinct id, SUM(amount) OVER(PARTITION BY id) as [SUM_forPARTITION]
from (
select 1 as id, 23 as amount
union all
select 1 as id, 23 as amount
union all
select 2 as id, 11 as amount
union all
select 2 as id, 11 as amount
union all
select 3 as id, 8 as amount
union all
select 4 as id, 7 as amount
) OverPARTITIONID
Join the original table to the sum with a subquery:
SELECT * FROM table1, (SELECT SUM(amount) FROM table1 AS amount) t
This does just one sum() query, so it should perform OK:
SELECT a.id, b.amount
FROM table1 a
cross join (SELECT SUM(amount) as amount FROM table1 AS amount) b
in case someone else has the same problem and without joining we can do the following
select *
,totcalaccepted=(select sum(s.acceptedamount) from cteresult s)
, totalpay=(select sum(s.payvalue) from cteresult s)
from cteresult t
end
Using Full Join -
case when you need sum of amount field from tableB and all data from tableA on behalf of id match.
SELECT a.amount, b.* FROM tableB b
full join (
select id ,SUM(amount) as amount FROM tableA
where id = '1' group by id
) a
on a.id = b.id where a.id ='1' or b.id = '1' limit 1;