Case statement to determine if I should union - sql

I currently want to do some sort of conditional union. Given the following example:
SELECT age, name
FROM users
UNION
SELECT 25 AS age, 'Betty' AS name
Say I wanted to only union the second statement if the count of 'users' was >=2 , otherwise do not union the two.
In summary I want to append a table with a row if the table only has 2 or more values.

You could use an ugly hack something like this, but I think Tim's answer is better:
SELECT age, name
FROM users
UNION ALL
SELECT 25, 'Betty'
WHERE (SELECT COUNT(*) FROM users) > 1;

If it's in a stored-procedure you could use If...Else:
IF (SELECT COUNT(*) FROM users) < 2
BEGIN
SELECT age, name
FROM users
END
ELSE
SELECT age, name
FROM users
UNION ALL
SELECT 25 AS age, 'Betty' AS name
Otherwise you could try something like this:
SELECT age, name
FROM users
UNION ALL
SELECT TOP 1 25 AS age, 'Betty' AS name
FROM users
WHERE (SELECT COUNT(*) FROM users) >= 2
Note that i've used UNION ALL since it doesn't seem that you want to eliminate duplicates.
Played around here: http://sqlfiddle.com/#!6/a7540/2323/0
Edit: Instead of my second approach i prefer Zohar's. So if you can use If....Else prefer that otherwise WHERE (SELECT COUNT(*) FROM users) > 1 without a table.

Something like the following should work:
SELECT age, name
FROM users
UNION ALL
SELECT age, name
FROM (SELECT 25 AS age, 'Betty' AS name) x
CROSS APPLY (SELECT COUNT(*) FROM users) y(cnt)
WHERE y.cnt >= 2
Second part of UNION ALL will be NULL in case users table has less than 2 records.

SELECT age
, name
FROM users
UNION
SELECT 25 As age
, 'Betty' As name
WHERE EXISTS (
SELECT Count(*)
FROM users
HAVING Count(*) >= 2
)
;

Related

Perform Simple Group By in Google Big Query

i have the simplest query on google big query that keeps returning an error
Grouping by expressions of type STRUCT is not allowed
i am simply trying to select a list of emails from two locations, union them in one cte, and count frequency in the cte to identify duplicates.
this should be very easy - what am i missing??
with a as (select properties.email as email, 'loc1' as tag from `loc1.contacts`),
b as (select properties.email as email, 'loc2' as tag from `loc2.contacts`),
c as (
select * from a
union all
select * from b
)
select email, count(email) from c group by 1
sample data:
email/tag
bob#email.com/loc1
bob#email.com/loc2
expected results:
email/count
bob#email.com/2
looks like i needed to add .value to actually get the value of the email field, following query worked as desired
with a as (select properties.email.value as email, 'loc1' as tag from `loc1.contacts`),
b as (select properties.email.value as email, 'loc2' as tag from `loc2.contacts`),
c as (
select * from a
union all
select * from b
)
select email, count(email) from c group by 1

Can we use join with in same table while using group by function?

For instance, I have a table with columns below:
pk_id,address,first_name,last_name
and I have a query like this to display the first name ans last name that are repetitive(duplicates)
select first_name,last_name
from table
group by first_name,last_name
having count(*)>1;
but the above query just returns first and last names but I want to display pk_id and address too that are tied to these duplicate first and last names
Can we use joins to do this on the same table.Please help!!
A simple way of doing is to build a view with the pk_id and the count of duplicates. Once you have it, it is only a matter of using a JOIN on the base table, and a filter to only keep rows having a duplicate:
SELECT T.*
FROM T
JOIN (SELECT "pk_id",
COUNT(*) OVER(PARTITION BY "first_name", "last_name") cnt
FROM T) V
ON T."pk_id" = V."pk_id"
WHERE cnt > 1
See http://sqlfiddle.com/#!4/3ecd0/9
You have to call it from an outer query, like this:
select * from table
where first_name||last_name in
(select first_name||last_name from
(select first_name, last_name, count( * )
from table
group by first_name,last_name
having count( * ) > 1
)
)
note: you may not need to concatenate the 2 fields, but I haven't tested thaT.
with
my_duplicates as
(
select
first_name,
last_name
from
my_table
group by
first_name,
last_name
having
count(*) > 1
)
select
bb.pk_id,
bb.address,
bb.first_name,
bb.last_name
from
my_duplicates aa
join my_table bb on
(
aa.first_name = bb.first_name
and
aa.last_name = bb.last_name
)
order by
bb.last_name,
bb.first_name,
bb.pk_id

Get data origin after a UNION

I have a SQL query like this:
SELECT *
FROM (
(SELECT name FROM man)
UNION
(SELECT name FROM woman )
) AS my_table
ORDER BY name
how can I retrieve the source of my data?
For example if my result is like this:
Bob
Alice
Mario
...
I want to know if the name 'Bob' is retrieve from the 'man' table or from the 'woman' table.
SELECT *
FROM (
(SELECT name, 'man' as source FROM man)
UNION ALL
(SELECT name, 'woman' FROM woman )
) AS my_table
ORDER BY name
I added the UNION ALL becasue if these are mutually exclusive tables, it will be faster. If they are not, then adding the source will make the results mutually exclusive and you wil be able to see where the dups are. If they are not mutually exclusive but you only want to show one record, what business rule do you want to show which record you took?
A select can include a literal string, so the simplest way is probably to do:
SELECT *
FROM (
(SELECT name, 'man' as source FROM man)
UNION
(SELECT name, 'woman' as source FROM woman )
) AS my_table
ORDER BY name
These will only work if there is no intersection of Man & Woman.
If you expect duplicates, you will need to add some magic to the where clause.
and perhaps a 3rd query in the union to cover those where both exist.

Sql Query With GroupBys - Impossible Query

I have the following:
Name Age When
Paul 21 01-Jan-10
Paul 54 01-Jan-11
Paul 65 01-Jan-12
I want to pull out all names and that age wherer the date is >= 01-Jan-11
I ve tried
SELECT NAME, AGE, MIN(When)
FROM ATABLE
WHERE When >= '01-Jan-11'
GROUP BY NAME, AGE
That did not work - I get the 01 Jan 2011 AND 01 Jan 2012 for Paul which is wrong - I just want the one
NOTE: This comment is the most correct so far but does not provide an answer :(
You're where clause will get 2 records and will keep them as 2 records since you're grouping by Name and Age. If Name and Age were the same, it'd be 1 record and not 2.
WHEN is a SQL Server reserved word - if that is really your column name it might be causing you problems. In any case, it would be helpful to post more information, such as any errors you were receiving.
Also for what its worth, normally I would use DATEDIFF for the date comparison:
SELECT NAME, AGE, MIN(When)
FROM ATABLE
WHERE DATEDIFF ( 'd', '2001-01-01', When ) > 0
GROUP BY NAME, AGE
In SQL Server:
SELECT a.*
FROM (
SELECT DISTINCT name
FROM atable
) ad
CROSS APPLY
(
SELECT TOP 1 *
FROM atable ai
WHERE ai.name = ad.name
AND When >= '01-Jan-11'
ORDER BY
When
) a
try
SELECT NAME, AGE, MIN(When) FROM A TABLE WHERE When >= '2011/01/01' GROUP BY NAME, AG
http://www.databasejournal.com/features/mssql/article.php/2209321/Working-with-SQL-Server-DateTime-Variables-Part-Three---Searching-for-Particular-Date-Values-and-Ranges.htm
thats easy...
SELECT NAME, AGE, MIN(When)
FROM ATABLE
WHERE
YEAR([When]) >= 2011
AND MONTH([When]) >= 1
AND DAY([When]) >= 1
GROUP BY NAME, AGE
SELECT k.Name, t.Age, k.MinWhen
FROM (
SELECT Name, MIN(When) MinWhen
FROM ATABLE
GROUP BY Name
) k
JOIN ATABLE t ON
t.Name = k.Name
AND t.When = k.MinWhen

Add row to query result using select

Is it possible to extend query results with literals like this?
select name from users
union
select name from ('JASON');
or
select age, name from users
union
select age, name from (25,'Betty');
so it returns all the names in the table plus 'JASON', or (25,'Betty').
You use it like this:
SELECT age, name
FROM users
UNION
SELECT 25 AS age, 'Betty' AS name
Use UNION ALL to allow duplicates: if there is a 25-years old Betty among your users, the second query will not select her again with mere UNION.
In SQL Server, you would say:
Select name from users
UNION [ALL]
SELECT 'JASON'
In Oracle, you would say
Select name from user
UNION [ALL]
Select 'JASON' from DUAL
is it possible to extend query results with literals like this?
Yes.
Select Name
From Customers
UNION ALL
Select 'Jason'
Use UNION to add Jason if it isn't already in the result set.
Use UNION ALL to add Jason whether or not he's already in the result set.