mssql - select from another table if no results from the first table - sql-server

I have to run a query to find a price. I have multiple price lists, each in their own table. customer_price, default_price and minimum_price.
not all price lists have all the products and at times a product might not appear on any price list and then the price needs to return 0 for the price.
so I want to:
select price from customer_price where customer='walmart' and product='whitebread'
if this returns a result then all is well. if the result is 0,NULL or the query returns no rows I want this to run:
select price from default_price where customer='walmart' and product='whitebread'
if this returns a result then all is well. if the result is 0,NULL or the query returns no rows I want to simply return 0.
I am not sure how to proceed. I tried a case statement but the case statement fails if no row is found in the results. how can I do this or say if 0 results then
thanks in advance, as always.

select top 1 price from (
select 1 as qorder, price from customer_price where price > 0 and customer='walmart' and product='whitebread'
union
select 2 as qorder, price from default_price where price > 0 and customer='walmart' and product='whitebread'
union
select 3 as qorder, 0
) as sq
order by qOrder

case when
(select count(price) from customer_price where customer='walmart' and product='whitebread' and price is not null and price > 0) > 0
then
select price from customer_price where customer='walmart' and product='whitebread'
else
select price from default_price where customer='walmart' and product='whitebread'
end

I'm writing a two way solution which includes for both Empty Select Queries or Tables. You can replace your query
if OBJECT_ID('tempdb..#temp1') is not null
drop table #temp1
select * into #temp1 from (select col1, col2 from First_Table) as firstTableVariable
if (##ROWCOUNT > 0)
begin
print 'data is displayed from the first table/query'
select * from #temp1
end
else
begin
print 'Data displayed from second table/query '
select col1, col2 from second_Table
end
end

Related

Repeat last value of a column, when it is empty -SSRS

Can we repeat last value of a column in SSRS? As in attachment, all blank rows in
the last column should be filled with the latest value 702
I used Previous, Last functions but nothing helped
That's achievable if you do this:
Step 1. For your source, you build a sql query where you group the data by Year, AbsoluteMonth, etc.
So for each Year / AbsoluteMonth pair the report has only ONE value.
Step 2. Use below formula:
=IIf(IsNothing(Sum(Fields!Amt.Value)), Last(Fields!Amt.Value, "Year"), Sum(Fields!Amt.Value))
Here "Year" is group name, and Amt - your field name, which is probably R_Pax
Step3. (optional) Sort the data if it's not naturally sorted to provide the correct last value.
Step 1 is very important. Otherwise the cell with empty value will not show the last total, it will show the last value for a month, so if month (1) has values 30, 50, 60, and month (2) doesn't have any values, then it will show 60 for month(2), month(3), etc..., not sum(30+50+60).
You better insert the remaining blank records with last value into your dataset before pass the data to report.I assume your table is matrix.
DECLARE #Today DATETIME
SET #Today = GETDATE()
DECLARE #MatrixData TABLE (
Month1 INT
, Year1 INT
, Value INT
)
INSERT INTO #MatrixData (Month1, Year1, Value)
SELECT MONTH(DATEADD(MONTH, Id * -1, #Today)) AS Date1Month, YEAR(DATEADD(MONTH, Id * -1, #Today)) AS Date1Year, Id * 10 AS Value1
FROM (
SELECT TOP 60 ROW_NUMBER() OVER (ORDER BY Id) AS Id
FROM SysObjects
) A
ORDER BY Date1Year, Date1Month
SELECT * FROM #MatrixData
-- Insert blank month of last year with last value
INSERT INTO #MatrixData (Month1, Year1, Value)
SELECT A.RunningMonth, A1.MaxYear, A1.LastValue
FROM (
SELECT TOP 12 ROW_NUMBER() OVER (ORDER BY Id) AS RunningMonth
FROM SysObjects
) A
INNER JOIN (
-- Get Last Value in #MatrixData
SELECT A.MinMonth, A.MaxMonth, A.MaxYear, A1.Value AS LastValue
FROM (
-- Get Max Month Last Year in #MatrixData
SELECT MAX(A1.Month1) AS MinMonth, A.MaxMonth, A.MaxYear
FROM (
-- Get Max Month & Max Year
SELECT MAX(Month1) AS MaxMonth, MAX(Year1) AS MaxYear
FROM #MatrixData
) A
INNER JOIN #MatrixData A1 ON A.MaxYear = A1.Year1
GROUP BY A.MaxMonth, A.MaxYear
) A
INNER JOIN #MatrixData A1 ON A.MinMonth = A1.Month1 AND A.MaxYear = A1.Year1
) A1 ON A.RunningMonth > A1.MinMonth AND A.RunningMonth <= A1.MaxMonth
SELECT * FROM #MatrixData
We can do it at SQL end and fetch data to SSRS
Steps:
Do pivot if needed
Get the data at granularity column. Here it is Absolute Month
Then use the SQL method to replcae the Nulls/ last values which are empty with the last highest value
Ref:
`select a.AbsoluteMonth,Mon
,first_value(a.S1_pax)over(partition by a.v1_p order by num ) as S_Pax
,first_value(a.S2_pax)over(partition by a.v2_p order by num ) as S2_Pax`
from
(select *
,sum(case when S1_pax is null then 0 else 1 end) over (order by num) as v1_p
,sum(case when S2_pax is null then 0 else 1 end) over (order by num) as v2_p
from X_Table
)a
And fill all places respectively. Plz refer below output
In Oracle it is done like this. SQL Server has both COALESCE and LAG functions. So this must be possible with SQL Server also. There is also another stackoverflow question similar to this. Just could not locate it.
create table mytab(n number, m number);
insert into mytab values(1,null);
insert into mytab values(2,null);
insert into mytab values(3,44949);
insert into mytab values(4,null);
insert into mytab values(5,null);
insert into mytab values(6,null);
insert into mytab values(7,null);
insert into mytab values(8,null);
insert into mytab values(9,null);
insert into mytab values(10,null);
insert into mytab values(11,74631);
insert into mytab values(12,null);
insert into mytab values(13,null);
select t.*, coalesce(m, lag(m ignore nulls) over (order by n))
from mytab t;

Querying in SQL-

I have a table named "Results" like below:
I'd like to count personnel who have been completely scored. It means the ones who have no zero in score column. For example based on the uploaded picture just person with ID 1004 should be counted and the outcome should be one.
I used this code:
select Count(PrsID) from results
where Score <> 0
group by PrsID
But it wouldn't help me cause if a person has just one non-zero score, he will be counted!
Thanks in advance.
If I understand you correctly, I think this is what you want: SELECT COUNT(DISTINCT(PrsID)) FROM results WHERE PrsID NOT IN (SELECT DISTINCT PrsID FROM results WHERE score = 0)
If a person's min score is greater than zero, then they should be counted.
select count(1)
from (
select PrsID
from results
group by PrsID
having min(Score) > 0) as results
You can use conditional aggregation as below:
Select PrsId from results
group by PrsId
having sum(case when score = 0 then 1 else 0 end) > 1
I think you want something like:
select PrsID, Count(1) from results
where Score = 0
group by PrsID
This one returns count of person who has non zero score
SELECT
t1.PrsID,
Count(t1.PrsID)
FROM
( SELECT
*
FROM results
GROUP BY results.PrsID
ORDER BY results.Score ASC
) AS t1
WHERE t1.Score <> 0;

SQL stored procedure for picking a random sample based on multiple criteria

I am new to SQL. I looked for all over the internet for a solution that matches the problem I have but I couldn't find any. I have a table named 'tblItemReviewItems' in an SQL server 2012.
tblItemReviewItems
Information:
1. ItemReviewId column is the PK.
2. Deleted column will have only "Yes" and "No" value.
3. Audited column will have only "Yes" and "No" value.
I want to create a stored procedure to do the followings:
Pick a random sample of 10% of all ItemReviewId for distinct 'UserId' and distinct 'ReviewDate' in a given date range. 10% sample should include- 5% of the total population from Deleted (No) and 5% of the total population from Deleted (Yes). Audited ="Yes" will be excluded from the sample.
For example – A user has 118 records. Out of the 118 records, 17 records have Deleted column value "No" and 101 records have Deleted column value "Yes". We need to pick a random sample of 12 records. Out of those 12 records, 6 should have Deleted column value "No" and 6 should have Deleted column value "Yes".
Update Audited column value to "Check" for the picked sample.
How can I achieve this?
This is the stored procedure I used to pick a sample of 5% of Deleted column value "No" and 5% of Deleted column value "Yes". Now the situation is different.
ALTER PROC [dbo].[spItemReviewQcPickSample]
(
#StartDate Datetime
,#EndDate Datetime
)
AS
BEGIN
WITH CTE
AS (SELECT ItemReviewId
,100.0
*row_number() OVER(PARTITION BY UserId
,ReviewDate
,Deleted
order by newid()
)
/count(*) OVER(PARTITION BY UserId
,Reviewdate
,Deleted
)
AS pct
FROM tblItemReviewItems
WHERE ReviewDate BETWEEN #StartDate AND #EndDate
AND Deleted in ('Yes','No')
AND Audited='No'
)
SELECT a.*
FROM tblItemReviewItems AS a
INNER JOIN cte AS b
ON b.ItemReviewId=a.ItemReviewId
AND b.pct<=6
;
WITH CTE
AS (SELECT ItemReviewId
,100.00
*row_number() OVER(PARTITION BY UserId
,ReviewDate
,Deleted
ORDER BY newid()
)
/COUNT(*) OVER(PARTITION BY UserId
,Reviewdate
,Deleted
)
AS pct
FROM tblItemReviewItems
WHERE ReviewDate BETWEEN #StartDate AND #EndDate
AND deleted IN ('Yes','No')
AND audited='No'
)
UPDATE a
SET Audited='Check'
FROM tblItemReviewItems AS a
INNER JOIN cte AS b
ON b.ItemReviewId=a.ItemReviewId
AND b.pct<=6
;
END
Any help would be highly appreciated. Thanks in advance.
This may assist you in getting started. My idea is, you create the temp tables you need, and load the specific data into the (deleted, not deleted etc.). You then run something along the lines of:
IF OBJECT_ID('tempdb..#tmpTest') IS NOT NULL DROP TABLE #tmpTest
GO
CREATE TABLE #tmpTest
(
ID INT ,
Random_Order INT
)
INSERT INTO #tmpTest
(
ID
)
SELECT 1 UNION ALL
SELECT 2 UNION ALL
SELECT 3 UNION ALL
SELECT 4 UNION ALL
SELECT 5 UNION ALL
SELECT 6 UNION ALL
SELECT 7 UNION ALL
SELECT 8 UNION ALL
SELECT 9 UNION ALL
SELECT 10 UNION ALL
SELECT 11 UNION ALL
SELECT 12 UNION ALL
SELECT 13 UNION ALL
SELECT 14 UNION ALL
SELECT 15 UNION ALL
SELECT 16;
DECLARE #intMinID INT ,
#intMaxID INT;
SELECT #intMinID = MIN(ID)
FROM #tmpTest;
SELECT #intMaxID = MAX(ID)
FROM #tmpTest;
WHILE #intMinID <= #intMaxID
BEGIN
UPDATE #tmpTest
SET Random_Order = 10 + CONVERT(INT, (30-10+1)*RAND())
WHERE ID = #intMinID;
SELECT #intMinID = #intMinID + 1;
END
SELECT TOP 5 *
FROM #tmpTest
ORDER BY Random_Order;
This assigns a random number to a column, that you then use in conjunction with a TOP 5 clause, to get a random top 5 selection.
Appreciate a loop may not be efficient, but you may be able to update to a random number without it, and the same principle could be implemented. Hope that gives you some ideas.

Get COUNT() of rows where first 3 digits of column are alike

I have a result set of codes that are usually three digits followed by up to 2 digits like 012.34 or 123.45. The first three digits define a general category of group, and the digits following the decimal place define more specific qualities. There could be 77 012.xx numbers, and there are hundreds of unique 3 digit group definitions, followed by a varying number of digits per entry.
Does anyone know how to write a quick query to achieve this?
Assuming it is in a varchar column since you're storing 012.34...
SELECT LEFT(someColumn,3), COUNT(*)
FROM someTable
GROUP BY LEFT(someColumn,3)
HAVING COUNT(*) > 5 -- per your comments
ORDER BY LEFT(someColumn,3)
If it's not, then you'd do this:
SELECT LEFT(CONVERT(VARCHAR(10),someColumn),3), COUNT(*)
FROM someTable
GROUP BY LEFT(CONVERT(VARCHAR(10),someColumn),3)
ORDER BY LEFT(CONVERT(VARCHAR(10),someColumn),3)
#rypress these look strikingly similar to ICD-9 Diagnosis codes for Other respiratory tuberculosis ClickMe. Is this correct? In that case you will get Category and subcategory in your result and may change your counts(012->012.0->012.00,012.02..)
Sample Data:
IF OBJECT_ID(N'TempICD') > 0
BEGIN
DROP TABLE TempICD
END
CREATE TABLE TempICD (ICD VARCHAR(10))
INSERT INTO TempICD
VALUES ('012'),('012.0'),('012.00'),('012.01'),('012.02'),
('012.03'),('012.04'),('012.05'),('012.05'),
('013'),('013.0'),('013.00'),('013.01'),('013.02'),
('013.03'),(NULL)
Query to get Category with 6 or more line items (Including Category and Sub Category):
SELECT LEFT(ICD, 3) AS ICDs,
COUNT(1) AS ICDCount
FROM TempICD
GROUP BY LEFT(ICD, 3)
HAVING COUNT(*) > 5
ORDER BY LEFT(ICD, 3)
Query to get Category with 6 or more line items (Excluding Category and Sub Category):
SELECT SUBSTRING(ICD, 1, CHARINDEX('.', ICD + '.') - 1) AS ICDs,
SUM(CASE
WHEN LEN(SUBSTRING(ICD, CHARINDEX('.', ICD) + 1, LEN(ICD))) = 2 THEN 1
ELSE 0
END) AS ICDCount
FROM TempICD
WHERE ICD IS NOT NULL
GROUP BY SUBSTRING(ICD, 1, CHARINDEX('.', ICD + '.') - 1)
HAVING SUM(CASE
WHEN LEN(SUBSTRING(ICD, CHARINDEX('.', ICD) + 1, LEN(ICD))) = 2 THEN 1
ELSE 0
END) > 5
Cleanup Script:
IF OBJECT_ID(N'TempICD') > 0
BEGIN
DROP TABLE TempICD
END
This may also help you.
I assume that the column is Decimal Data type.
SELECT CAST([COLUMN] AS INT) [GROUP],
COUNT(*) [COUNT]
FROM [TABLE] T
GROUP BY CAST([COLUMN] AS INT)
it depends if your resultset is numeric or characters. if not numeric you can use string operations.
select left(resultSet,charindex('.',resultset)) , count(*)
from x
group by by left(resultSet,charindex('.',resultset))
order by left(resultSet,charindex('.',resultset))
with charindex you will get a correct 'cut' when the first digits are not 3 as 'usually'.
if your resultset is numeric/float you can use the floor function
select floor(resultset),count(*)
from x
group by floor(resultset)
order by floor(resultset)

If any clause when grouping

Doing a Sum() on a column adds up the values in that column based on group by. But lets say I want to sum these values only if all the values are not null or not 0, then I need a clause which checks if any of the values is 0 before it does the sum. How can I implement such a clause?
I'm using sql server 2005.
Thanks,
Barry
Let's supose your table schema is:
myTable( id, colA, value)
Then, one approach is:
Select colA, sum(value)
from myTable
group by colA
having count( id ) = count( nullif( value, 0 ))
Notice that nullif is a MSSQL server function. YOu should adapt code to your rdbms brand.
Explanation:
count aggregate function only count not null values. Here a counting null values test.
You say that 0+2+3=0 for this case. Assuming that NULL+2+3 should also be zero:
SELECT GroupField,
SUM(Value) * MIN(CASE WHEN COALESCE(Value, 0) = 0 THEN 0 ELSE 1 END)
FROM SumNonZero
GROUP BY GroupField
The above statement gives this result
GroupField (No column name)
case1 5
case2 0
case3 0
with this test data
CREATE TABLE SumNonZero (
GroupField CHAR(5) NOT NULL,
Value INT
)
INSERT INTO SumNonZero(GroupField, Value)
SELECT 'case1', 2
UNION ALL SELECT 'case1', 3
UNION ALL SELECT 'case2', 0
UNION ALL SELECT 'case2', 2
UNION ALL SELECT 'case2', 3
UNION ALL SELECT 'case3', NULL
UNION ALL SELECT 'case3', 3
UNION ALL SELECT 'case3', 4
It makes no sense to eliminate 0 from a SUM because it wont impact the sum.
But you may want to SUM based on another field:
select FIELD, sum(
case when(OTHER_FIELD>0) then FIELD
else 0
end)
from TABLE
group by TABLE

Resources