How do I get this with only One Query/SubQuery - c#

I have this database table:
Name Beneficiary GenderBeneficiary
---------------------------------------
Karla Karla Female
Carl Mandy Female
Mark Lu Male
Erik Math Male
Jhon Jhon Male
And I need this
Gender
Description Male Female Total
-------------------------------------------
Employee 1 1 2
Familiar 2 1 3
Total 3 2 5
If the name is the same of the beneficiary is an Employee, if not is a familiar.
I get a nice result using UNION with 4 queries and the structure in SQL Server is:
Updated: stored procedure used
USE [BdDiscountCardSystem]
GO
SET ANSI_NULLS ONGO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[FillTableOne]
#dateStart DATETIME,
#dateEnd DATETIME
AS
BEGIN
SET NOCOUNT ON;
SELECT
COUNT (GenderBeneficiary) AS Gender
FROM
CartaDescuento
WHERE
Name = BeneficiaryName
AND GenderBeneficiary = 'Male'
AND DateS BETWEEN #dateStart AND #dateEnd
UNION
SELECT
COUNT (GenderBeneficiary)
FROM
CartaDescuento
WHERE
Name = BeneficiaryName
AND GenderBeneficiary = 'Female'
AND DateS BETWEEN #dateStart AND #dateEnd
UNION
SELECT
COUNT (GenderBeneficiary)
FROM
CartaDescuento
WHERE
Name != BeneficiaryName
AND GenderBeneficiary = 'Male'
AND DateS BETWEEN #dateStart AND #dateEnd
UNION
SELECT
COUNT (GenderBeneficiary)
FROM
CartaDescuento
WHERE
Name != BeneficiaryName
AND GenderBeneficiary = 'Female'
AND DateS BETWEEN #dateStart AND #dateEnd
END
The result:
Title
1
2
1
1
I'm calling the stored procedure from C# like this:
public void GetTableOne()
{
string dateStart = dateInicio.Value.ToShortDateString();
string dateEnd = dateFinal.Value.ToShortDateString();
try
{
con.Open();
SqlCommand cmd = new SqlCommand("FillTableOne", con);
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("dateStart", dateStart);
cmd.Parameters.AddWithValue("dateEnd", dateEnd);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "¡Error!", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
finally
{
con.Close();
}
}
Updated: but I only get 1 query, not the UNIONS in the stored procedure:
Title
1
Updated: I didn't put the query or the code, because that doesn't work. I'm looking for help in structuring that in a single query. I assumed that it was not necessary to put anything other than the tables and the result that I want, in this way to be able to accommodate the columns as the report requires.
Well, anyone know a better option to get in only one query?
Additional question: I'm reporting with iTextSharp and is kinda tedious typing 120 code lines to get and structure one simple table. Any suggestions on how to get a better reporter in C#?

This isn't exactly the structure you asked for but it gets back all of the data in one query:
SELECT
SUM(CASE WHEN Name != Beneficiary AND GenderBeneficiary= 'Female' THEN 1 ELSE 0 END) AS [FemaleFamiliars],
SUM(CASE WHEN Name != Beneficiary AND GenderBeneficiary= 'Male' THEN 1 ELSE 0 END) AS [MaleFamiliars],
SUM(CASE WHEN Name = Beneficiary AND GenderBeneficiary= 'Female' THEN 1 ELSE 0 END) AS [FemaleEmployees],
SUM(CASE WHEN Name = Beneficiary AND GenderBeneficiary= 'Male' THEN 1 ELSE 0 END) AS [MaleEmployees],
SUM(CASE WHEN GenderBeneficiary= 'Female' THEN 1 ELSE 0 END) AS [TotalFemales],
SUM(CASE WHEN GenderBeneficiary= 'Male' THEN 1 ELSE 0 END) AS [TotalMales],
SUM(CASE WHEN Name != Beneficiary THEN 1 ELSE 0 END) AS [TotalFamiliar],
SUM(CASE WHEN Name = Beneficiary THEN 1 ELSE 0 END) AS [TotalEmployees],
COUNT(*) AS [GrandTotal]
FROM Employees

Here is another approach to this. It requires two queries and a UNION ALL but not a huge deal. It is actually quite a few less characters than the previous answer. :)
declare #Something table
(
Name varchar(10)
, Beneficiary varchar(10)
, GenderBeneficiary varchar(10)
)
insert #Something values
('Karla', 'Karla', 'Female')
,('Carl', 'Mandy', 'Female')
,('Mark', 'Lu', 'Male')
,('Erik', 'Math', 'Male')
,('Jhon', 'Jhon', 'Male')
select case when s.Name = s.Beneficiary then 'Employee' else 'Familiar' end
, sum(case when GenderBeneficiary = 'Male' then 1 end)
, sum(case when GenderBeneficiary = 'Female' then 1 end)
, count(*)
from #Something s
group by case when s.Name = s.Beneficiary then 'Employee' else 'Familiar' end
UNION ALL
select Description = 'Total'
, sum(case when GenderBeneficiary = 'Male' then 1 end)
, sum(case when GenderBeneficiary = 'Female' then 1 end)
, count(*)
from #Something s

Related

Creating an Oracle view that takes a parameter

I have a very long query:
SELECT TO_CHAR(tsc.id) AS status,
CASE WHEN tsc.description IS NULL THEN CAST('' as NVARCHAR2(50)) ELSE tsc.description END AS description,
SUM(CASE WHEN tr.USER_TYPE = 1 THEN 1 ELSE 0 END) AS "1",
SUM(CASE WHEN tr.USER_TYPE = 2 THEN 1 ELSE 0 END) AS "2",
SUM(CASE WHEN tr.USER_TYPE = 3 THEN 1 ELSE 0 END) AS "3",
SUM(CASE WHEN tr.USER_TYPE = 5 THEN 1 ELSE 0 END) AS "5",
SUM(CASE WHEN tr.USER_TYPE IS NOT NULL THEN 1 ELSE 0 END) AS total
FROM TRANSACTION_STATUS_CODES tsc
LEFT JOIN TRANSACTIONS tr ON tsc.id = tr.status AND tr.User_Type BETWEEN 1 AND 5 AND tr.status != 1 AND tr.update_date BETWEEN TO_DATE('2022-01-01', 'yyyy-mm-dd HH24:MI:SS') AND TO_DATE('2023-01-04', 'yyyy-mm-dd HH24:MI:SS')
LEFT JOIN TRANSACTION_USER_TYPES ut ON ut.id = tr.user_type
WHERE tsc.id != 1
GROUP BY tsc.id, tsc.description
UNION ALL
SELECT 'TOTAL 2,4,5' AS status,
NULL AS description,
SUM(CASE WHEN tr.USER_TYPE = 1 THEN 1 ELSE 0 END),
SUM(CASE WHEN tr.USER_TYPE = 2 THEN 1 ELSE 0 END),
SUM(CASE WHEN tr.USER_TYPE = 3 THEN 1 ELSE 0 END),
SUM(CASE WHEN tr.USER_TYPE = 5 THEN 1 ELSE 0 END),
SUM(CASE WHEN tr.USER_TYPE IS NOT NULL THEN 1 ELSE 0 END) AS total
FROM TRANSACTION_STATUS_CODES tsc
LEFT JOIN TRANSACTIONS tr ON tsc.id = tr.status AND tr.User_Type BETWEEN 1 AND 5 AND tr.status != 1 AND tr.update_date BETWEEN TO_DATE('2022-01-01', 'yyyy-mm-dd HH24:MI:SS') AND TO_DATE('2023-01-04', 'yyyy-mm-dd HH24:MI:SS')
LEFT JOIN TRANSACTION_USER_TYPES ut ON ut.id = tr.user_type
WHERE tsc.id != 1 AND tsc.id IN (2, 4, 5)
UNION ALL
SELECT 'Total for All' AS status,
NULL AS description,
SUM(CASE WHEN tr.USER_TYPE = 1 THEN 1 ELSE 0 END),
SUM(CASE WHEN tr.USER_TYPE = 2 THEN 1 ELSE 0 END),
SUM(CASE WHEN tr.USER_TYPE = 3 THEN 1 ELSE 0 END),
SUM(CASE WHEN tr.USER_TYPE = 5 THEN 1 ELSE 0 END),
SUM(CASE WHEN tr.USER_TYPE IS NOT NULL THEN 1 ELSE 0 END) AS total
FROM TRANSACTION_STATUS_CODES tsc
LEFT JOIN TRANSACTIONS tr ON tsc.id = tr.status AND tr.User_Type BETWEEN 1 AND 5 AND tr.status != 1 AND tr.update_date BETWEEN TO_DATE('2022-01-01', 'yyyy-mm-dd HH24:MI:SS') AND TO_DATE('2023-01-04', 'yyyy-mm-dd HH24:MI:SS')
LEFT JOIN TRANSACTION_USER_TYPES ut ON ut.id = tr.user_type
WHERE tsc.id != 1
That does what it does.
I've been asked to save it as view and just "Select * from view" which is nice...
but as you can see I run
AND tr.update_date BETWEEN TO_DATE('2022-01-01', 'yyyy-mm-dd HH24:MI:SS') AND TO_DATE('2023-01-04', 'yyyy-mm-dd HH24:MI:SS')
This line of code few times there. now. If I save it as view it will just be same result over and over.
I have this csharp code:
requestedDateTable = LocalGeneralDbExecuterService1.call_TransactionsReport_StoredProcedure(fromDateStr, toDateStr);
which is a function that stores the query above in a datatable variable with two dates I'm capturing from two different labels and gives me a modified result set based on those dates.
I'm trying to achieve the same kind of workflow but without having to write dozens lines of query code in my program.
Is that possible? If so, how? I've been trying procedures, views... and my SQL knowledge isn't WOW at all.
From 19.6 you can create SQL table macros. In effect these enable you to create parameterized views.
Here's an example based on the standard HR schema:
create or replace function filter_emps (
start_date date, end_date date
)
return clob sql_macro as
begin
return '
select * from hr.employees
where hire_date >= start_date and hire_date < end_date ';
end filter_emps;
/
select employee_id, hire_date
from filter_emps ( date'2003-01-01', date'2003-06-01' );
/*
EMPLOYEE_ID HIRE_DATE
----------- -----------------
115 18-MAY-2003 00:00
122 01-MAY-2003 00:00
*/
var start_date varchar2(10);
var end_date varchar2(10);
exec :start_date := '2005-01-01'
exec :end_date := '2005-03-01';
select employee_id, hire_date
from filter_emps (
to_date ( :start_date, 'yyyy-mm-dd' ), to_date ( :end_date, 'yyyy-mm-dd' )
);
/*
EMPLOYEE_ID HIRE_DATE
----------- -----------------
131 16-FEB-2005 00:00
142 29-JAN-2005 00:00
146 05-JAN-2005 00:00
150 30-JAN-2005 00:00
185 20-FEB-2005 00:00
*/
Views cannot take parameters.
Instead, you can write a stored procedure that takes the start and end dates as parameters and returns a cursor.
CREATE PROCEDURE procedure_name (
i_start_date IN TRANSACTIONS.UPDATE_DATE%TYPE,
i_end_date IN TRANSACTIONS.UPDATE_DATE%TYPE,
o_cursor OUT SYS_REFCURSOR
)
IS
BEGIN
OPEN o_cursor FOR
<your_query>;
END procedure_name;
/
and replace the hard-coded dates with:
AND tr.update_date BETWEEN i_start_date AND i_end_date
Then you can call the procedure from C# and pass the parameters.
As already explained, views cannot take parameters.
Another approach suiting your requirements could be a table function:
-- define a type fitting your output
create type t_my_row as object (
id number,
description varchar2(50)
);
create type t_my_tab is table of t_my_row;
-- write a procedure with the required parameters
create function get_my_tab(i_start_date in date, i_end_date in date) return t_my_tab as
l_tab t_my_tab := t_my_tab();
begin
-- your selection here: (select ... union all select...)
for l_rec in (select id, descr from mytable where update_date between i_start_date and i_end_date) loop
l_tab.extend;
l_tab(l_tab.last) := t_my_row(l_rec.id, l_rec.description);
end loop;
return l_tab;
end;
-- call it:
select * from table(get_my_tab(sysdate-1, sysdate));

I have a small registration Form with 4 fields

The fields are
employeeID int
name varchar
Gender int (0 = male, 1 = female)
Date datetime
Now if i am writing select query like this
select employeeID,name,Gender,Date
from empTable
where employeeID=#id
I get result
'101','cccc','1','11/1/2014'
But i need a query its give me
'101','cccc','Female','11/1/2014'
If this is Sql Server you can use a CASE statement.
select employeeID
,name
,case when Gender = 1 then 'Female' else 'Male' end AS Gender
,Date
from empTable
where employeeID=#id
IIF statement
select employeeID
,name
, IIF(Gender = 1, 'Female', 'Male') AS Gender
,Date
from empTable
where employeeID=#id

SQL: Running two queries at once and Assigning Variables

I am basically trying to run these two queries:
SELECT * FROM ProductTable;
SELECT CAST(CASE WHEN COUNT(*) > 0 THEN 1 ELSE 0 END AS BIT)
FROM UserTable WHERE id = 41;
Both queries work properly. The first one returns me all the data in ProductTable. The second query returns me either 1 or 0 after checking if the row ID 41 exists
Running them together:
SELECT * FROM ProductTable SELECT CAST(CASE WHEN COUNT(*) > 0 THEN 1 ELSE 0 END AS BIT)
FROM UserTable WHERE id = 41
However, when I run this, the second query does not return any value, this is because I have not set a SQL variable name to it.
How can I set a Variable name to the second query such that I can read that value when reading the SQL response?
DECLARE #val BIT
SELECT #val = CAST(CASE WHEN COUNT(*) > 0 THEN 1 ELSE 0 END AS BIT)
FROM UserTable WHERE id = 41
SELECT P.*, #val FROM ProductTable P
If you need either 1 or 0 after checking if the row ID 41 exists then (following Pinwar13 answer) this code performs better, needn't count all rows
DECLARE #val BIT = CASE WHEN EXISTS (SELECT 1 FROM UserTable WHERE id = 41)
THEN 1 ELSE 0 END;
SELECT P.*, #val FROM ProductTable P
Try like this,
SELECT *
,(
SELECT CAST(CASE
WHEN COUNT(*) > 0
THEN 1
ELSE 0
END AS BIT)
FROM UserTable
WHERE id = 41
) AS UserCount
FROM ProductTable;
you can use cross apply also..
SELECT p.*,t.[BIT] FROM ProductTable p
CROSS APPLY (SELECT CAST(CASE WHEN COUNT(*) > 0 THEN 1 ELSE 0 END AS [BIT])
FROM UserTable WHERE id = 41)t

SQL comparison between 3 columns

I have 3 columns in my database. (1) Buy/Sell (2) ID (3) Date and time. For example:
buySel ID Date
1 234 12/12/2014
1 234 12/12/2014
2 234 12/12/2014
In buySell the number (1) is represented as buy and (2) is sell. Within the same day if the ID e.g. '234' is bought and sold this should return a error message.
This is what I have done in C#
string connectionString= "connection string goes here";
string Query = "SELECT COUNT(*) AS sum from databaseTable WHERE created_time >= DATEADD(hour, 9, CONVERT(DATETIME, CONVERT(DATE, GETDATE())))";
........
SqlDataReader data;
try
{
con.Open();
myReader = cmdg.ExecuteReader();
while (data.Read())
{
if (myReader[0].ToString() != "0")
{
MessageBox.Show("Error " + myReader[0].ToString());
}
}
}
catch (Exception e)
{
MessageBox.Show(e.Message);
}
I managed to compare it with today's date however how will I compare it to the buySell column and the ID column?
I'm not sure exactly what you want to return. The following will identify all the errors in your data, based on having a buy and sell in the same day:
select id, date
from databaseTable t
group by id, date
having sum(case when buysel = 1 then 1 else 0 end) > 0 and
sum(case when buysel = 2 then 1 else 0 end) > 0;
I'll like #GordonLinoff's answer, but haven't compared it performance wise to what you would get from a using EXISTS with correlated subqueries.
create table databaseTable (buySel TINYINT, ID INT, [Date] DATE)
insert into databaseTable values
(1,234,'12/12/2014'),
(1,234,'12/12/2014'),
(2,234,'12/12/2014')
select id
,[Date]
from databaseTable a
where exists(select 1 from databaseTable b where b.id=a.id
and b.[Date] = a.[Date]
and buysel = 1)
and exists(select 1 from databaseTable b where b.id=a.id
and b.[Date] = a.[Date]
and buysel = 2)
group by id
,[Date]
In this query the group by serves only as a more efficient DISTINCT.
EDIT:
Since the above statement has been questioned I figure I should examine it more closely. There a lot of discussion here and on the web at large. I think the sum of the guidance would be that GROUP BY is often more efficient then DISTINCT, but not always and DISTINCT is more intuitive a syntax.
Huge performance difference when using group by vs distinct
When the performance of Distinct and Group By are different?
http://msmvps.com/blogs/robfarley/archive/2007/03/24/group-by-v-distinct-group-by-wins.aspx

How count the 1's and 0's with a bit return type and return it in two separate columns

I would like my sql query to select all the fields in a table by one date or between two dates, 3 of the fields in my database have the return type as bits. This is somewhat my database looks
ID||Name || Surname || Age || Country || SumOfInfection || SumOfOtherInfection|| HasPersonContacted
SumOfInfection, SumOfOtherInfection& HasPersonContacted have the return type of bits. For these three fields i; need to sum the numbers of True(1) and False(0) into two separate columns.
Name|| Surname|| .... ||HasPersonContacted(sum of 1's based on a userID) || HasPersonContacted(sum of 0's based on a userID) .....
so what i am looking for
SumOfInfection <- all the 1's for that ID
output= 10 <- so the person had 10 infection
SumOfInfection <- all the 0's for that ID
output= 3 - so the person had no infection for 3 times
i would like to do same for SumOfOtherInfection and HasPersonContacted .
This is what i have done but it only shows the sum of SumOfInfection how do i get all these data in one go? i rely like to use Select * because in future if i am looking for more data i dont have to rewrite my query.
SELECT COUNT(NULLIF(SumOfInfection,1))
From [TableName]
where ID='1234' AND Cast([Time] AS DATE) >'2012-01-09' AND CAST([Time] AS DATE) < '2014-01-01'
Try using conditional sum():
SELECT sum(case when SumOfInfection = 1 then 1 else 0 end) as NumInfection1,
sum(case when SumOfInfection = 0 then 1 else 0 end) as NumInfection0
From [TableName]
where ID='1234' AND Cast([Time] AS DATE) >'2012-01-09' AND CAST([Time] AS DATE) < '2014-01-01' ;
Alternatively, you can cast the bit as an integer:
SELECT sum(cast(SumOfInfection as int)) as NumInfection1,
sum(1 - cast(SumOfInfection as int)) as NumInfection1
EDIT:
I think the full query is more like:
select Name, Surname,
sum(case when HasPersonContacted = 1 then 1 else 0 end) as NumPersonContacted1,
sum(case when HasPersonContacted = 0 then 1 else 0 end) as NumPersonContacted0,
. . .
from t
group by Name, Surname;

Categories

Resources