Test Data
Name count percentage location
ABC 2 100.00% india
ABC 1 90.00% us
ABC 4 50.00% null
ABC 3 100.00% uk
I want to append the count of location null records with india location and need to remove the null records?
Means 3rd row having location as null then need to append the count (4) with india count i.e(2+4=6) .
Please suggest anyone how to achieve this result using sql?
below solution takes max percentage
( select name,count,percentage,location
from testdate
where location is not null and location<>'india'
)
union all
( select name,sum(count),max(percentage),max(location)
from testdate
where location='india' or location is null
group by name
)
Just use a CASE to change NULL to INDIA, and then a GROUP BY to add the COUNT
SQL Fiddle Demo
SELECT "Name", SUM("count"), MAX("percentage"), "location"
FROM (
SELECT "Name",
"count",
CASE WHEN "location" IS NULL THEN ''
ELSE "percentage"
END as "percentage",
CASE WHEN "location" IS NULL or "location" = 'india' THEN 'india'
ELSE "location"
END as "location"
FROM Table1
) T
GROUP BY "location", "Name";
OUTPUT
| Name | sum | max | location |
|------|-----|---------|----------|
| ABC | 1 | 90.00% | us |
| ABC | 6 | 100.00% | india |
| ABC | 3 | 100.00% | uk |
EDIT:
The second CASE can be replace by
COALESCE("location", 'india') as "location"
Try something like this
select name,sum(count),max(percentage),coalesce(location,'India')
from Yourtable
group by name,coalesce(location,'India')
Currently it will take the MAX percentage out of NULL or India
Related
I have table 1 data and I need to create another column as on criteria
If id has "-" or "any letters" bring value from invoice
Table1
+---------+---------+
| id | invoice |
+---------+---------+
| 1234 | 2534 |
| 9870 | 6542 |
| ABC234 | 9874 |
| 34-5469 | 325416 |
+---------+---------+
Expected Result as id2
+---------+---------+--------+
| id | invoice | id2 |
+---------+---------+--------+
| 1234 | 2534 | 1234 |
| 9870 | 6542 | 9870 |
| ABC234 | 9874 | 9874 |
| 34-5469 | 325416 | 325416 |
+---------+---------+--------+
You can use isnumeric function to find out whether the id is int or not.
select *,
case when isnumeric(id) = 1 then id else invoice end as id2
from [yourtable]
Edit: isnumeric is not providing credible results all the time and hence if you are using SQL server 2012 or 2014 and above you may go for try_cast
select *
,case when try_cast(id as int) is not null then id else invoice end as id2
from [yourtable]
Assuming that you are just looking for values that have a letter or a hyphen (-) you could use a CASE expression and a LIKE like this:
SELECT CASE WHEN id LIKE '%[A-z-]%' THEN invoice ELSE id END
FROM dbo.YourTable;
What would likely be better, however, is to check that id doesn't value any characters apart from digits:
SELECT CASE WHEN id LIKE '%[^0-9]%' THEN invoice ELSE id END
FROM dbo.YourTable;
I ran into this problem because I'm using grouping sets in a subquery that gives me this results
name | objective | vehicle | count_of_installed
------------------------------------------------------
Antonio | | | 1
Antonio | 40 | 2nd vehicle | 19
Antonio | NULL | NULL | 20
George | | | 10
George | 50 | 2nd vehicle | 20
George | NULL | NULL | 30
And I'm then only searching only for rows where there are nulls, as they are the correct count_of_installed, now I want to have the correct objective and vehicle replacing the NULL values with the correct values, so I thought of something like coalesce(objective, objective), but I'm not sure this works.
For reference, my grouping sets are:
grouping sets (name, (name, objective, vehicle))
Edit 1
In my example above is the result of a query with joining my seller and sales tables, it shouldn't show neither blank nor null values, so when I say coalesce(objective, objective), I mean replace the null results from the result table with the correct values from my seller table.
I have a scenario. There are two Tables TABLE-A and TABLE-B. The source is TABLE-A. The destination is TABLE-B. I want to compare the ID with self join. If ID is matching i want to ensure only NOT NULL value is picked. If both records has NULL value then Null value can be considered as ouput.
Below scenario,
TABLE-A has one duplicate ID i.e 1. In output i will be have one value for that duplicate record and merge data intelligently that NULL VALUES are excluded and if both records are having NULL for any column then NULL will be populated in TABLE-B.
TABLE A
ID NAME ADDRESS PHONE STATUS PROCESSFLAG
1 YOU XYZ NULL NULL 1
2 PQR ABC 123 Active 2
1 YOU NULL 322 NULL 2
OUTPUT TABLE B
ID NAME ADDRESS PHONE STATUS PROCESSFLAG
2 PQR ABC 123 Active 2
1 YOU XYZ 322 NULL 2
You can group by id and select max() for each column to exclude nulls:
insert into tableb(id, name, address, phone, status, processflag)
select id, max(name), max(address), max(phone), max(status), max(processflag)
from tablea
group by id
I assume that your problem is the nulls and the non null columns of the duplicates have the same value in different rows or you want the maximum of the 2 values like your sample data.
See the demo.
Results:
ID | NAME | ADDRESS | PHONE | STATUS | PROCESSFLAG
-: | :--- | :------ | :---- | :----- | ----------:
1 | YOU | XYZ | 322 | null | 2
2 | PQR | ABC | 123 | Active | 2
Let's say I have following (fictional) dataset
ID | Name | Location | LastUpdated
1 | Bill | Germany | 2017-01-02
2 | Bill | Germany | 2017-01-03
3 | Bill | Germany | 2017-01-04
4 | Bill | Germany | 2017-01-05
5 | Jack | U.K | 2017-01-02
6 | Jack | U.K | 2017-01-03
7 | Jack | U.K | 2017-01-04
8 | John | Japan | 2017-02-22
9 | John | Japan | 2017-02-23
10 | John | Japan | 2017-02-24
11 | John | Japan | 2017-02-25
With my dataset I want to remove all records where lastupdated equals 2017-01-03
I also want to remove all of John's records where lastupdated equal or is greater then 2017-02-24
I tried following SQL statement:
SELECT *
FROM Table
WHERE (LastUpdated <> '2017-01-03')
AND (Name <> 'John' AND LastUpdated >= '2017-02-24')
But this way, it only returns the records with a LastUpdated greater then 2017-02-24
It seems pretty basic, but I can't work it out. Any ideas?
You can transcript your requirements like this:
I want to remove all records where lastupdated equals 2017-01-03
This is correct from your attempt:
LastUpdated <> '2017-01-03'
I also want to remove all of John's records where lastupdated equal or
is greater then 2017-02-24
This one is a little trickier. Either the record we want to display isn't John's OR the record is John's AND the date has to be lower than 2017-02-24. This is expressed like the following:
(
Name <> 'John' OR
(Name = 'John' AND LastUpdated < '2017-02-24')
)
So the final expression would be:
SELECT *
FROM [Table]
WHERE
LastUpdated <> '2017-01-03' AND
(
Name <> 'John' OR
(Name = 'John' AND LastUpdated < '2017-02-24')
)
Also if name can hold NULL values, you might need another OR expression that checks for NULL:
(
Name <> 'John' OR
Name IS NULL OR
(Name = 'John' AND LastUpdated < '2017-02-24')
)
You can write it as a NOT condition to keep it simple:
WHERE NOT (
(lastupdated = 2017-01-03)
OR
(name = 'John' AND lastupdated >= '2017-02-24')
)
let's supose I have this table in my db:
----------------------------------
| userID | meta | value |
|--------------------------------|
| 1 | age | 20 |
| 1 | gender | M |
| 1 | country | Brazil |
| 2 | age | 21 |
| 3 | age | 22 |
| 3 | gender | F |
| 3 | country | Brazil |
----------------------------------
And I want to get all userID that are from Brazil and the age is more than 18 years...
I tried something similar to this:
SELECT distinct(userID)
FROM table
WHERE (meta = age AND value > 18) AND (meta = country AND value = 'Brazil')
But this didn't work, which is the right way to do this?
Thanks
The way you wrote your query, means that you want to have (meta > 18) and (country = Brazil) all on the same line. But that never happens, since your table is not built like that.
You can do this to query on one meta/value pair:
SELECT userID
FORM User
WHERE (meta = 'age' AND value > 18)
But if you want to query on two meta/value pairs, you have to join the table unto itself, like so:
SELECT a.userID
FROM User AS a
JOIN User AS b ON a.userID = b.userID
WHERE (a.meta = 'age' AND a.value > 18)
AND (b.meta = 'country' AND b.value = 'Brazil')
This way, it "virtually creates" a table where you would have two meta values and two age values in each line. You can use WHERE conditions to verify conditions on two pairs of meta and value.
The above query results in userID = 1 and = 3 (from the sample data you put in the question).
select userID
from Users
group by userID
having max(case when meta = 'age' and cast(value as int) = 18 then 1 end) = 1
and max(case when meta = 'country' and value = 'Brazil' then 1 end) = 1