Check all values in another column (NULL or NOT NULL ) and return unique records - sql

As you see for cid=1 all date fields are NULL and for cid=3 all date fields are NOT NULL.
I need get unique cids with new field, if all dates are NULL then with "NULL" and if all dates are NOT NULL then with "NOT NULL".
cid - new field
1 - NULL
3 - NOT NULL

You can do this with aggregation and case:
select cid,
(case when count(datecol) = 0 then 'NULL'
when count(datecol) = count(*) then 'NOT NULL'
end) as newField
from t
group by cid
having count(datecol) in (0, count(*));

select cid, case when min(c) = 0 AND max(c) = 0 then 'null' when min(c) = 1 and max(c) = 1 then 'not null' end from (
select cid, case when dt is null then 0 else 1 end as c from your_table
) t
group by cid
having min(c) = max(c)

Related

skip null or 0 value while using row_number sql server

i am trying to get row_number from the data, but i want to skip the null or 0 value
DECLARE #ProcessId INT = 6013006
DECLARE #CommHeaderId int
SELECT #CommHeaderId = a.id
FROM EprocUltimate.dbo.commercial_header a
WHERE a.process_id = #ProcessId
SELECT b.rank_quotation, c.rank_nego,
CASE ISNULL(a.quotation_usd, 0) WHEN 0 THEN a.quotation_idr ELSE a.quotation_usd END As Quotation,
CASE ISNULL(a.nego_usd, 0) WHEN 0 THEN a.nego_idr ELSE a.nego_usd END As Nego
FROM EprocUltimate.dbo.commercial_vendor a
INNER JOIN
(
SELECT a.id, ROW_NUMBER() OVER(ORDER BY CASE quotation_usd WHEN 0 THEN quotation_idr ELSE quotation_usd END ASC) AS rank_quotation
FROM EprocUltimate.dbo.commercial_vendor a
WHERE a.commercial_header_id = #CommHeaderId AND a.commercial_admin_bid_evaluation_result = 'Pass'
) b ON a.id = b.id
INNER JOIN
(
SELECT a.id, ROW_NUMBER() OVER(ORDER BY CASE ISNULL(nego_usd, 0) WHEN 0 THEN nego_idr ELSE nego_usd END ASC) AS rank_nego
FROM EprocUltimate.dbo.commercial_vendor a
WHERE a.commercial_header_id = #CommHeaderId AND a.commercial_admin_bid_evaluation_result = 'Pass'
) c ON a.id = c.id
WHERE a.commercial_header_id = #CommHeaderId AND a.commercial_admin_bid_evaluation_result = 'Pass'
ORDER BY b.rank_quotation
heres the result
rank_quotation rank_nego, value1, value2
1 3 775460000.00 770000000.00
2 1 781036525.00 NULL
3 2 786250000.00 NULL
from this query what i want is to get row_numbering the rank_nego with having value first
so the result that i want to achive is
rank_quotation rank_nego, value1, value2
1 1 775460000.00 770000000.00
2 2 781036525.00 NULL
3 3 786250000.00 NULL
You can use a little workaround to have your NULL values as last records in your subquery with the ROW_NUMBER() OVER (ORDER BY ...) as rank_nego
(
SELECT a.id, ROW_NUMBER() OVER(ORDER BY
-- This statement will first sort records having nego_usd and nego_idr as NULL/0 at the end of the list
CASE WHEN ISNULL(nego_usd, 0) = 0 AND ISNULL(nego_idr, 0) = 0 THEN 1 ELSE 0 END ASC,
-- and then sort with the real values
CASE ISNULL(nego_usd, 0) WHEN 0 THEN nego_idr ELSE nego_usd END ASC
) AS rank_nego
FROM EprocUltimate.dbo.commercial_vendor a
WHERE a.commercial_header_id = #CommHeaderId AND a.commercial_admin_bid_evaluation_result = 'Pass'
) c ON a.id = c.id

SQL : Group by and check if all, some or none are set

Lets say I have the following table:
FKEY A B C D E F
'A' 1 0 1 0 1 0
'A' 0 1 1 1 0 0
Now i want to make a group by FKEY but I just want to know if the A-F columns has 1 in one, all or none of the grouped rows.. The resulton the above table would be:
FKEY A B C D E F
'A' S S A S S N
..where S is "some", A is "all" and N is "none".
What would be the best approach to make this query. I could so some nested queries, but isnt there a smarter way?
In my real life data, the 1's and 0's are actually DATETIME and NULL's
You can use case and aggregation:
select fkey,
(case when sum(a) = 0 then 'N'
when sum(a) = count(*) then 'A'
else 'S'
end) as a,
(case when sum(b) = 0 then 'N'
when sum(b) = count(*) then 'A'
else 'S'
end) as b,
. . .
from t
group by fkey;
The above assumes that the values are only 0 and 1. If that is the case, you can actually phrase this as:
(case when max(a) = 0 then 'N'
when min(a) = 1 then 'A'
else 'S'
end) as a,
You mentioned that your 0 and 1 are actually null or non null dates. Here's a modified version of Gordon's query that caters for that:
select fkey,
(case when count(datecol) = 0 then 'all dates are null'
when count(datecol) = count(*) then 'all dates are filled'
else 'some are null, some filled'
end) as a,
...
from t
group by fkey;
COUNT(null) is 0, COUNT('2001-01-01') is 1, COUNT(*) is the row count independent of any variable. Hence, if our count of the dates was 0, all must be null. If the count of the dates was equal to the count of the rows, then all must be filled with some value, otherwise it's a mix

To get one record if mre than one record exists for same id ,then get only one record based on below condition

e.g. If I get 2 null data in a column for same id, then pass null.
ii) If I get 2 same not null data in a column for same id, then pass not null.
ii) If I get 1 null and 1 not null data in a column for same id, then pass not null.
ii) If I get 2 different not null data in a column for same id, then pass '?'.
Sample data
Please find the sample data in the image.
Thanks in advance.
Output obtained after new code:
Result
You can try following :
SELECT (CASE WHEN PRTY_KEY_ID_NN= 0 THEN NULL /* IF BOTH/ALL VALUES ARE NULL */)
WHEN PRTY_KEY_ID_NN <> TOTAL_COUNT THEN PRTY_KEY_ID_NN_MX
ELSE
CASE WHEN TOTAL_COUNT=PRTY_KEY_ID_NN_DIST THEN NULL /* IF BOTH HAVING DIFFERENT NOT NULL VALUE */
CASE WHEN TOTAL_COUNT<>PRTY_KEY_ID_NN_DIST THEN PRTY_KEY_ID_NN_MX
END
END)PRTY_KEY_ID_VAL,
(CASE WHEN TOTAL_ASSET_A_NN= 0 THEN NULL /* IF BOTH/ALL VALUES ARE NULL */)
WHEN TOTAL_ASSET_A_NN <> TOTAL_COUNT THEN TOTAL_ASSET_A_MX
ELSE
CASE WHEN TOTAL_COUNT=TOTAL_ASSET_A_DIST THEN NULL /* IF BOTH HAVING DIFFERENT NOT NULL VALUE */
CASE WHEN TOTAL_COUNT<>TOTAL_ASSET_A_DIST THEN TOTAL_ASSET_A_MX
END
END)TOTAL_ASSET_VAL,
(CASE WHEN DBUS_NUM_NN= 0 THEN NULL /* IF BOTH/ALL VALUES ARE NULL */)
WHEN DBUS_NUM_NN <> TOTAL_COUNT THEN DBUS_NUM_MX
ELSE
CASE WHEN TOTAL_COUNT=DBUS_NUM_DIST THEN NULL /* IF BOTH HAVING DIFFERENT NOT NULL VALUE */
CASE WHEN TOTAL_COUNT<>DBUS_NUM_DIST THEN DBUS_NUM_MX
END
END)DBUS_NUM_DIST_VAL,
(CASE WHEN BUS_NATURE_DE_NN= 0 THEN NULL /* IF BOTH/ALL VALUES ARE NULL */)
WHEN BUS_NATURE_DE_NN <> TOTAL_COUNT THEN BUS_NATURE_DE_MX
ELSE
CASE WHEN TOTAL_COUNT=BUS_NATURE_DE_DIST THEN NULL /* IF BOTH HAVING DIFFERENT NOT NULL VALUE */
CASE WHEN TOTAL_COUNT<>BUS_NATURE_DE_DIST THEN BUS_NATURE_DE_MX
END
END)BUS_NATURE_DE_VAL
FROM
(SELECT COUNT(*)TOTAL_COUNT,
SUM(CASE WHEN PRTY_KEY_ID IS NULL THEN 0 ELSE 1 END)PRTY_KEY_ID_NN,
SUM(CASE WHEN TOTAL_ASSET_A IS NULL THEN 0 ELSE 1 END)TOTAL_ASSET_A_NN,
SUM(CASE WHEN TOTAL_LIAB_A IS NULL THEN 0 ELSE 1 END)TOTAL_LIAB_A_NN,
SUM(CASE WHEN DBUS_NUM IS NULL THEN 0 ELSE 1 END)DBUS_NUM_NN,
SUM(CASE WHEN BUS_NATURE_DE IS NULL THEN 0 ELSE 1 END)BUS_NATURE_DE_NN,
MAX(PRTY_KEY_ID_NN)PRTY_KEY_ID_NN_MX,
MAX(TOTAL_ASSET_A)TOTAL_ASSET_A_MX,
MAX(TOTAL_LIAB_A)TOTAL_LIAB_A_MX,
MAX(DBUS_NUM)DBUS_NUM_MX,
MAX(BUS_NATURE_DE)BUS_NATURE_DE_MX,
COUNT(DISTINCT PRTY_KEY_ID_NN) PRTY_KEY_ID_NN_DIST,
COUNT(DISTINCT TOTAL_ASSET_A)TOTAL_ASSET_A_DIST,
COUNT(DISTINCT TOTAL_LIAB_A)TOTAL_LIAB_A_DIST,
COUNT(DISTINCT DBUS_NUM)DBUS_NUM_DIST,
COUNT(DISTINCT BUS_NATURE_DE)BUS_NATURE_DE_DIST
FROM YOUR_TABLE)
You can find out the sample data like image in below SQL.If the column data type is varchar(char) please delete the TO_CHAR expression, and replace the table name TEST_TABLE to your table's.
WITH TEST_TABLE AS (
SELECT 1056059 AS PRTY_KEY_ID, NULL AS TOT_ASSET_AM, NULL AS TOT_LIABILITIES_AM, NULL AS DBUS_NM, 'Pediatrics' AS BUS_NATURE_DE FROM DUAL
UNION ALL
SELECT 1056059 AS PRTY_KEY_ID, 5000 AS TOT_ASSET_AM, '300000' AS TOT_LIABILITIES_AM, NULL AS DBUS_NM, 'Medicine' AS BUS_NATURE_DE FROM DUAL
)
SELECT
PRTY_KEY_ID,
MIN(CASE WHEN TOT_ASSET_AM_CNT > 1 THEN '?' ELSE TO_CHAR(TOT_ASSET_AM) END) AS TOT_ASSET_AM,
MIN(CASE WHEN TOT_LIABILITIES_AM_CNT > 1 THEN '?' ELSE TO_CHAR(TOT_LIABILITIES_AM) END) AS TOT_LIABILITIES_AM,
MIN(CASE WHEN DBUS_NM_CNT > 1 THEN '?' ELSE TO_CHAR(DBUS_NM) END) AS DBUS_NM,
MIN(CASE WHEN BUS_NATURE_DE_CNT > 1 THEN '?' ELSE TO_CHAR(BUS_NATURE_DE) END) AS BUS_NATURE_DE
FROM (
SELECT
TEST_TABLE.*,
COUNT(TOT_ASSET_AM) OVER(PARTITION BY PRTY_KEY_ID) AS TOT_ASSET_AM_CNT,
COUNT(TOT_LIABILITIES_AM) OVER(PARTITION BY PRTY_KEY_ID) AS TOT_LIABILITIES_AM_CNT,
COUNT(DBUS_NM) OVER(PARTITION BY PRTY_KEY_ID) AS DBUS_NM_CNT,
COUNT(BUS_NATURE_DE) OVER(PARTITION BY PRTY_KEY_ID) AS BUS_NATURE_DE_CNT
FROM TEST_TABLE
)
GROUP BY PRTY_KEY_ID

Counting if data exists in a row

Hey guys I have the below sample data which i want to query for.
MemberID AGEQ1 AGEQ2 AGEQ2
-----------------------------------------------------------------
1217 2 null null
58458 3 2 null
58459 null null null
58457 null 5 null
299576 6 5 7
What i need to do is to lookup the table and if any AGEx COLUMN contains any data then it counts the number of times there is data for that row in each column
Results example:
for memberID 1217 the count would be 1
for memberID 58458 the count would be 2
for memberID 58459 the count would be 0 or null
for memberID 58457 the count would be 1
for memberID 299576 the count would be 3
This is how it should look like in SQL if i query the entire table
1 Children - 2
2 Children - 1
3 Children - 1
0 Children - 1
So far i have been doing it using the following query which isnt very efficient and does give incorrect tallies as there are multiple combinations that people can answer the AGE question. Also i have to write multiple queries and change the is null to is not null depending on how many children i am looking to count a person has
select COUNT (*) as '1 Children' from Member
where AGEQ1 is not null
and AGEQ2 is null
and AGEQ3 is null
The above query only gives me an answer of 1 but i want to be able to count the other columns for data as well
Hope this is nice and clear and thank you in advance
If all of the columns are integers, you can take advantage of integer math - dividing the column by itself will yield 1, unless the value is NULL, in which case COALESCE can convert the resulting NULL to 0.
SELECT
MemberID,
COALESCE(AGEQ1 / AGEQ1, 0)
+ COALESCE(AGEQ2 / AGEQ2, 0)
+ COALESCE(AGEQ3 / AGEQ3, 0)
+ COALESCE(AGEQ4 / AGEQ4, 0)
+ COALESCE(AGEQ5 / AGEQ5, 0)
+ COALESCE(AGEQ6 / AGEQ6, 0)
FROM dbo.table_name;
To get the number of people with each count of children, then:
;WITH y(y) AS
(
SELECT TOP (7) rn = ROW_NUMBER() OVER
(ORDER BY [object_id]) - 1 FROM sys.objects
),
x AS
(
SELECT
MemberID,
x = COALESCE(AGEQ1 / AGEQ1, 0)
+ COALESCE(AGEQ2 / AGEQ2, 0)
+ COALESCE(AGEQ3 / AGEQ3, 0)
+ COALESCE(AGEQ4 / AGEQ4, 0)
+ COALESCE(AGEQ5 / AGEQ5, 0)
+ COALESCE(AGEQ6 / AGEQ6, 0)
FROM dbo.table_name
)
SELECT
NumberOfChildren = y.y,
NumberOfPeopleWithThatMany = COUNT(x.x)
FROM y LEFT OUTER JOIN x ON y.y = x.x
GROUP BY y.y ORDER BY y.y;
I'd look at using UNPIVOT. That will make your wide column into rows. Since you don't care about what value was in a column, just the presence/absence of value, this will generate a row per not-null column.
The trick then becomes mashing that into the desired output format. It could probably have been done cleaner but I'm a fan of "showing my work" so that others can conform it to their needs.
SQLFiddle
-- Using the above logic
WITH HadAges AS
(
-- Find everyone and determine number of rows
SELECT
UP.MemberID
, count(1) AS rc
FROM
dbo.Member AS M
UNPIVOT
(
ColumnValue for ColumnName in (AGEQ1, AGEQ2, AGEQ3)
) AS UP
GROUP BY
UP.MemberID
)
, NoAge AS
(
-- Account for those that didn't show up
SELECT M.MemberID
FROM
dbo.Member AS M
EXCEPT
SELECT
H.MemberID
FROM
HadAges AS H
)
, NUMBERS AS
(
-- Allowable range is 1-6
SELECT TOP 6
ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) AS TheCount
FROM
sys.all_columns AS SC
)
, COMBINATION AS
(
-- Link those with rows to their count
SELECT
N.TheCount AS ChildCount
, H.MemberID
FROM
NUMBERS AS N
LEFT OUTER JOIN
HadAges AS H
ON H.rc = N.TheCount
UNION ALL
-- Deal with the unlinked
SELECT
0
, NA.MemberID
FROM
NoAge AS NA
)
SELECT
C.ChildCount
, COUNT(C.MemberID) AS Instances
FROM
COMBINATION AS C
GROUP BY
C.ChildCount;
Try this:
select id, a+b+c+d+e+f
from ( select id,
case when age1 is null then 0 else 1 end a,
case when age2 is null then 0 else 1 end b,
case when age3 is null then 0 else 1 end c,
case when age4 is null then 0 else 1 end d,
case when age5 is null then 0 else 1 end e,
case when age6 is null then 0 else 1 end f
from ages
) as t
See here in fiddle http://sqlfiddle.com/#!3/88020/1
To get the quantity of persons with childs
select childs, count(*) as ct
from (
select id, a+b+c+d+e+f childs
from
(
select
id,
case when age1 is null then 0 else 1 end a,
case when age2 is null then 0 else 1 end b,
case when age3 is null then 0 else 1 end c,
case when age4 is null then 0 else 1 end d,
case when age5 is null then 0 else 1 end e,
case when age6 is null then 0 else 1 end f
from ages ) as t
) ct
group by childs
order by 1
See it here at fiddle http://sqlfiddle.com/#!3/88020/24

Joining two select queries from the same table

The table contains an ID column, valueHeading column and a value column. I want to separate the value column into two new columns called valueHeading1 and valueHeading2 depending on which type of valueHeading the value has.
So I want to join this select:
Edit: Full join
SELECT ID
,valueHeading
,value as 'valueHeading1'
FROM table1
WHERE valueHeading = 'valueHeading1'
With This select:
SELECT ID
,value as 'valueHeading2'
FROM table1
WHERE valueHeading = 'valueHeading2'
on their respective ID's. How do I do this?
Edit to illustrate what I want to do:
Original table:
ID valueHeading value
0 valueHeading1 a
0 valueHeading2 a
1 valueHeading1 ab
1 valueHeading2 NULL
2 valueHeading1 abcd
2 valueHeading2 abc
New Table:
ID valueHeading1 valueHeading2
0 a a
1 ab NULL
2 abcd abc
If you need only join use this. Using case when is elegant way if you don't need join.
SELECT * FROM
(SELECT ID
,valueHeading
,value as 'valueHeading1'
FROM table1
WHERE valueHeading = 'valueHeading1') AS TAB_1,
(SELECT ID
,value as 'valueHeading2'
FROM table1
WHERE valueHeading = 'valueHeading2') AS TAB_2
WHERE TAB_1.ID = TAB_2.ID
Try something like :
SELECT ID
, CASE WHEN valueHeading = 'valueHeading1' THEN value ELSE NULL END AS valueHeading1
, CASE WHEN valueHeading = 'valueHeading2' THEN value ELSE NULL END AS valueHeading2
FROM table1
WHERE valueHeading IN ('valueHeading1', 'valueHeading2')
If you want to regroup all values on one row for each ID, you can try :
SELECT ID
, MAX(CASE WHEN valueHeading = 'valueHeading1' THEN value ELSE NULL END) AS valueHeading1
, MAX(CASE WHEN valueHeading = 'valueHeading2' THEN value ELSE NULL END) AS valueHeading2
FROM table1
WHERE valueHeading IN ('valueHeading1', 'valueHeading2')
GROUP BY ID
HAVING MAX(CASE WHEN valueHeading = 'valueHeading1' THEN value ELSE NULL END) IS NOT NULL
OR MAX(CASE WHEN valueHeading = 'valueHeading2' THEN value ELSE NULL END) IS NOT NULL
See SQLFiddle. I also tried on Oracle 11g and MSSQL 2012, and it works each time.
In SQLServer2005+ possible use PIVOT
SELECT ID, valueHeading1, valueHeading2
FROM
(
SELECT *
FROM dbo.test28
WHERE valueHeading IN ('valueHeading1', 'valueHeading2')
) x
PIVOT
(
MAX(value)
FOR valueHeading IN ([valueHeading1], [valueHeading2])
) p
Demo on SQLFiddle
self join could be a simple solution
SELECT DISTINCT t1.ID, t1.value as valueHeading1, t2.value as valueHeading2,
FROM table1 t1
INNER JOIN table1 t2 ON t1.ID = t2.ID
WHERE t1.valueHeading <> t2.valueHeading