Combining the Result of Two Select SQL Queries involving Joins - sql

I need to combine these two SQL queries to find the total count of empty & non empty tables in a given schema.
The below query produces two result outputs - which is correct.
But how I can join two of these select statements together as one single query statement with two result outputs?
I have tried using Union, Union all, Intersect all, and it will not give me the results I am looking for.
--- query for Empty tables:
select count (*) from
(
select schema_name(tab.schema_id) + '.' + tab.name as [emptytable]
from sys.tables tab
inner join sys.partitions part
on tab.object_id = part.object_id
where part.index_id IN (1, 0) -- 0 - table without PK, 1 table with PK
group by schema_name(tab.schema_id) + '.' + tab.name
having sum(part.rows) = 0
) as subquery;
--- query for Non-Empty tables:
select count (*) from
(
select schema_name(tab.schema_id) + '.' + tab.name as [non_emptyTable]
from sys.tables tab
inner join sys.partitions part
on tab.object_id = part.object_id
where part.index_id IN (1, 0) -- 0 - table without PK, 1 table with PK
group by schema_name(tab.schema_id) + '.' + tab.name
having sum(part.rows) > 0
) as subquery;

Use conditional aggregation:
select sum(case when size = 0 then 1 else 0 end) as num_empty,
sum(case when size > 0 then 1 else 0 end) as num_nonempty
from (select schema_name(tab.schema_id) + '.' + tab.name as table_name,
sum(part.rows) as size
from sys.tables tab join
sys.partitions part
on tab.object_id = part.object_id
where part.index_id in (1, 0) -- 0 - table without PK, 1 table with PK
group by schema_name(tab.schema_id) + '.' + tab.name
) t

Related

Set table name in a SELECT statement from a nested select

I have a table in MSSQL which has been called tables_list, it has a list of tables.
How can I use this list in another SELECT to count number of rows in each table and reach a list like the following picture:
SELECT T.[TABLE_NAME], count(*) AS NUMBERS
FROM [db_name].[schema_name].[T.[TABLE_NAME]]
(SELECT [TABLE_NAME],
FROM [db_name].[schema_name].[tables_list]) T
in sql server you can use system partition table to get the row counts in a database :
SELECT * FROM
(SELECT
QUOTENAME(SCHEMA_NAME(sOBJ.schema_id)) + '.' + QUOTENAME(sOBJ.name) AS [TableName],
SUM(sPTN.Rows) AS [RowCount]
FROM
sys.objects AS sOBJ
INNER JOIN sys.partitions AS sPTN ON sOBJ.object_id = sPTN.object_id
WHERE
sOBJ.type = 'U'
AND sOBJ.is_ms_shipped = 0x0
AND index_id < 2 -- 0:Heap, 1:Clustered
GROUP BY
sOBJ.schema_id,
sOBJ.name
ORDER BY [TableName]) X
WHERE X.[TableName] IN
(SELECT
CONCAT('[schema_name].[prefix', [TABLE_NAME], ']')
FROM [db_name].[schema_name].[tables_list])

How to use keyset pagination?

Suppose I have total 800 eligible rows in database which is ordered by a column requisitionid in descending order. I want to display the records in 80 pages each page having 10 rows. We are using requisitionid as seek predicate. So the predicate should be less than or greater than? As the query will progress from UI (Angular + primeNG), I want to send just one parameter - requisitionid. If it is less than query, then the query will be SELECT ... FROM ... where requisitionid < ?, so here we are talking about first row. If we go for greater than query i.e. SELECT ... FROM ... where requisitionid > ?, here we are talking about last row of the page.
Please refer to Life without offset
EDIT
Actual code:
with topten as (SELECT DISTINCT TOP 10
REQN.CASE_ID
,userContact2.BV_First_Name + ' ' + userContact2.BV_Last_Name ReQCreater
,REQN.BV_Internal_Job_Title
,REQN.BV_Posted_Job_Title as postedJobTitle
,REQN.BV_Status
,REQN.BV_Taleo_Id
,REQN.BV_WD_PositionID
,jobcode.BV_Job_Code
,loc.BV_LocationCode
,loc.BV_LocationName
,D.BV_Division_Code AS 'divCode',
ISNULL(loc.BV_Address1,'') + CASE WHEN ISNULL(loc.BV_Address1,'') = '' THEN '' ELSE ', ' END + ISNULL(loc.BV_Address2,'') + CASE WHEN ISNULL(loc.BV_Address2,'') = '' THEN '' ELSE ', ' END
+ ISNULL(loc.BV_City,'') + CASE WHEN ISNULL(loc.BV_City,'') = '' THEN '' ELSE ', ' END + ISNULL(loc.BV_State,'') + CASE WHEN ISNULL(loc.BV_State,'') = '' THEN '' ELSE (case when ISNULL(loc.BV_ZipCode,'') = '' THEN '' ELSE ', ' END) END
+ ISNULL(loc.BV_ZipCode,'') AS locationAddress
from dbo.CW_V_REQN as REQN
INNER JOIN dbo.CW_TL_Requisition__Location_Master as reqLocLink on REQN.CASE_ID = reqLocLink.FROM_ID
INNER JOIN dbo.CW_V_LOCTMAST as loc on loc.CASE_ID = reqLocLink.TO_ID
INNER JOIN dbo.CW_TL_UserContactInfo__Location_Master as locUserLink on locUserLink.TO_ID = loc.CASE_ID
INNER JOIN dbo.CW_V_USERCONT as userContact on userContact.CASE_ID = locUserLink.FROM_ID
LEFT JOIN dbo.CW_TL_Requisition__Department as reqDeptLink on REQN.CASE_ID = reqDeptLink.FROM_ID
INNER JOIN dbo.CW_V_DEPARTME as dept on dept.CASE_ID = reqDeptLink.TO_ID
LEFT JOIN dbo.CW_TL_UserContactInfo__Department_Master as deptUserLink on dept.CASE_ID=deptUserLink.TO_ID
INNER JOIN dbo.CW_TL_Requisition__Job_Code as reqJobLink on REQN.CASE_ID = reqJobLink.FROM_ID
LEFT JOIN dbo.CW_V_JOBCODE as jobcode on jobcode.CASE_ID = reqJobLink.TO_ID
LEFT JOIN dbo.CW_V_USERCONT as userContact2 on (userContact2.BV_Login_Name = REQN.CREATED_BY)
LEFT JOIN CW_TL_LocationMaster__Division_Master LD ON (LD.FROM_ID = loc.CASE_ID)
LEFT JOIN CW_V_DIVISION D ON (D.CASE_ID = LD.TO_ID)
WHERE userContact.BV_Login_Name = #LOGINNAME
AND REQN.CASE_ID < #MINCASEIDPREVPAGE
ORDER BY REQN.CASE_ID DESC
)
select topten.*
, T.*
from topten
cross join (select min(case_id) as min from topten) as T
For key based pagination on a descending key, the WHERE clause predicate should be < for the next page and > for the previous page. Also, the ORDER BY clause for the previous page needs to be ASC (for the TOP predicate) along an outer DESC (for the descending key display sequence). Below is an example.
--create test table with sample data
CREATE TABLE dbo.YourTable(
requisitionid int PRIMARY KEY
);
WITH
t10 AS (SELECT n FROM (VALUES(0),(0),(0),(0),(0),(0),(0),(0),(0),(0)) t(n))
,t1000 AS (SELECT ROW_NUMBER() OVER (ORDER BY (SELECT 0)) AS num FROM t10 AS a CROSS JOIN t10 AS b CROSS JOIN t10 AS c)
INSERT INTO dbo.YourTable WITH(TABLOCKX)
SELECT num
FROM t1000
WHERE num <= 800;
GO
--query for first page (page 1) on descending key (returns 800-791)
SELECT TOP(10) requisitionid
FROM YourTable
ORDER BY requisitionid DESC;
GO
--query for next page (page 2) on descending key (returns 790-781)
DECLARE #LastRequisitionIdOnPage int = 791;
SELECT TOP(10) requisitionid
FROM YourTable
WHERE requisitionid < #LastRequisitionIdOnPage
ORDER BY requisitionid DESC;
GO
--query for previous page (page 1) on descending key (returns 800-791)
DECLARE #FirstRequisitionIdOnPage int = 790;
SELECT requisitionid
FROM (
SELECT TOP(10) requisitionid
FROM YourTable
WHERE requisitionid > #FirstRequisitionIdOnPage
ORDER BY requisitionid ASC
) AS prev_page
ORDER BY requisitionid DESC;;
GO
If I understand your question, you should be able to use the follow clause at the end of your SELECT query:
OFFSET (#Page * 10) ROWS FETCH NEXT 10 ROWS ONLY
If this is not what you are looking for, please post your current query so we can see what you are doing now.

SQL how to deal with no values

When I run the query below
SELECT
COUNT(COALESCE(CASE PARTPPHY.TITRE
WHEN 1 THEN 'Monsieur '
WHEN 2 THEN 'Madame '
WHEN 3 THEN 'Madame '
ELSE ''
END + PARTPPHY.IDENTITE, PARTPPHY.IDENTITE)) AS ident,
RESPONSABLES.DIR_LOC,
PARTPPHY.IU_PART_PP,
COALESCE(CASE PARTPPHY.TITRE
WHEN 1 THEN 'Monsieur '
WHEN 2 THEN 'Madame '
WHEN 3 THEN 'Madame '
ELSE ''
END + PARTPPHY.IDENTITE,PARTPPHY.IDENTITE) AS IDENTITE,
FONCTIONS_ECO.LIBEL AS LIBEL_FONCTION
FROM
RESPONSABLES
INNER JOIN
ETABLISSEMENTS ON ETABLISSEMENTS.IU_ETS = RESPONSABLES.IU_ETS
LEFT OUTER JOIN
PARTPPHY ON RESPONSABLES.IU_PART_PP = PARTPPHY.IU_PART_PP
LEFT OUTER JOIN
FONCTIONS_ECO ON FONCTIONS_ECO.IU_FONC_ECO = RESPONSABLES.IU_FONC
WHERE
ETABLISSEMENTS.IU_ETS = 14783
AND RESPONSABLES.GESTDEL = 1
GROUP BY
RESPONSABLES.DIR_LOC,
PARTPPHY.IU_PART_PP,
COALESCE(CASE PARTPPHY.TITRE WHEN 1 THEN 'Monsieur ' WHEN 2 THEN 'Madame ' WHEN 3 THEN 'Madame ' ELSE '' END + PARTPPHY.IDENTITE,PARTPPHY.IDENTITE),
FONCTIONS_ECO.LIBEL
This is my result
Yet when I'm using this query
SELECT COUNT(COALESCE(CASE PARTPPHY.TITRE
WHEN 1 THEN 'Monsieur '
WHEN 2 THEN 'Madame '
WHEN 3 THEN 'Madame '
ELSE '' END + PARTPPHY.IDENTITE,PARTPPHY.IDENTITE)) AS ident,
RESPONSABLES.DIR_LOC,
PARTPPHY.IU_PART_PP,
COALESCE(CASE PARTPPHY.TITRE WHEN 1 THEN 'Monsieur ' WHEN 2 THEN 'Madame ' WHEN 3 THEN 'Madame ' ELSE '' END + PARTPPHY.IDENTITE,PARTPPHY.IDENTITE) AS IDENTITE,
FONCTIONS_ECO.LIBEL AS LIBEL_FONCTION
FROM RESPONSABLES
INNER JOIN ETABLISSEMENTS ON ETABLISSEMENTS.IU_ETS = RESPONSABLES.IU_ETS
LEFT OUTER JOIN PARTPPHY ON RESPONSABLES.IU_PART_PP = PARTPPHY.IU_PART_PP
LEFT OUTER JOIN FONCTIONS_ECO ON FONCTIONS_ECO.IU_FONC_ECO = RESPONSABLES.IU_FONC
WHERE ETABLISSEMENTS.IU_ETS = 1
AND RESPONSABLES.GESTDEL = 1
GROUP BY RESPONSABLES.DIR_LOC,
PARTPPHY.IU_PART_PP,
COALESCE(CASE PARTPPHY.TITRE WHEN 1 THEN 'Monsieur ' WHEN 2 THEN 'Madame ' WHEN 3 THEN 'Madame ' ELSE '' END + PARTPPHY.IDENTITE,PARTPPHY.IDENTITE),
FONCTIONS_ECO.LIBEL
I have this
My questions are the following:
It does not seem to be a null nor an empty space: What is it?
I want to have a value in my count: What should I do to have this?
Thanks
While using a COUNT without a GROUP BY clause you will always return a row, even if the WHERE clause is not equal to any of the records in your table. But while using a GROUP BY clause , it will return the records only if the WHERE clause condition is true.
Please check the following test scripts
DECLARE #TEST TABLE(ID INT)
INSERT INTO #TEST VALUES(10)
--1.
SELECT COUNT(*) FROM #TEST WHERE ID = 11 --Result is 0
--2.
SELECT COUNT(*),ID FROM #TEST WHERE ID = 11 GROUP BY ID --No Result
Here the first query always return a result
(No column name)
0
But second query not.
You can modify your second query something like the below script to get a '0' result
SELECT ISNULL(( SELECT COUNT(*) FROM #TEST WHERE ID = 11 GROUP BY ID ),0)
There is one more valid option. In both cases you are using the INNER JOIN, which is exclusive join meaning, if the join condition is not satisfied then no data is return, or more precise your result is an empty set.
Your INNER JOIN condition is on ETABLISSEMENTS.IU_ETS = RESPONSABLES.IU_ETS
In the first query your where statement says
WHERE ETABLISSEMENTS.IU_ETS = 14783 AND RESPONSABLES.GESTDEL = 1
This is where you have an empty data set
And in the second query your where statement is
WHERE ETABLISSEMENTS.IU_ETS = 1 AND RESPONSABLES.GESTDEL = 1
So to answer your first query:
Possibly there is no matching record, which has the ETABLISSEMENTS.IU_ETS = 14783 AND RESPONSABLES.GESTDEL = 1 therefore we are getting an empty set
In the second case the where statement is satisfied and there is a corresponding entry in both tables therefore we have a result.
Depending which side of the Join you are interested in, i.e. in which table yo will expect the row to be present you can switch the
JOIN to OUTER JOIN (LEFT or RIGHT)
The outer join is inclusive, meaning that it will return all rows from the table left or right to the join even if there is no record in corresponding table.
Then apply count on the corresponding table, i.e. id column. If there is no record then you will get 0
Example to illustrate
CREATE TABLE #Left
(
id INT
,col1 CHAR(3)
)
CREATE TABLE #Right
(
id INT
,col2 CHAR(3)
)
INSERT INTO #Right
( id, col2)
VALUES
(1,'c1')
,(2,'c2')
,(3,'c4')
,(4,'c5')
INSERT INTO #Left
( id, col1)
VALUES
(1,'c1')
,(2,'c2')
,(3,'c3')
,(4,'c5')
-- empty set
SELECT
*
FROM #Left L
INNER JOIN #Right R
ON L.col1 = R.col2
WHERE col1 = 'c3'
-- matching rows
SELECT
*
FROM #Left L
INNER JOIN #Right R
ON L.col1 = R.col2
WHERE col1 = 'c2'
-- Left Join
SELECT
L.*
,COUNT(R.col2)
FROM #Left L
LEFT JOIN #Right R
ON L.col1 = R.col2
WHERE col1 = 'c3'
GROUP BY L.id, L.col1

Can someone explain me what is the difference between union All and join in oracle SQL

I am searching for this question since last 2 days what is the difference between UNION and JOIN. Specifically UNION ALL and Natural JOIN.
So I have 2 queries here
first one is
CREATE OR REPLACE VIEW VU_m1 AS
SELECT department_id,manager_id FROM employees
NATURAL JOIN departments ;
SELECT * FROM vu_m1;
and the second one is
CREATE OR REPLACE VIEW VU_m2 AS
SELECT department_id,manager_id FROM employees
UNION ALL
SELECT department_id,manager_id FROM departments;
SELECT * FROM vu_m2;
The result from both the query is exactly same.
So now what is the difference between UNION ALL and Natural JOIN
Details:
I am using Oracle 11gR2 working on Sample HR database.
This is my 2 cents
+----------------------------------+--------------------------------------------+
+- UNION +- JOIN +
+----------------------------------+--------------------------------------------+
+SELECT 1 AS bah FROM DUAL + SELECT * +
+ EMP.DEPTNO + FROM +
+SELECT 2 AS bah FROM DUAL; + (SELECT 1 AS bah from dual) foo +
+ + JOIN +
+ + (SELECT 2 AS bah from dual) bar +
+ + ON 1=1; +
+----------------------------------+--------------------------------------------+
+- RESULTS +
+----------------------------------+--------------------------------------------+
+This gives everything in vertical + This gives everything in horizontal +
+ BAH + BAH BAH +
+ 1 + 1 2 +
+ 2 + +
+----------------------------------+--------------------------------------------+
+- OBSERVATIONS +
+----------------------------------+--------------------------------------------+
+ UNION puts lines from queries + JOIN makes a Cartesian product +
+ after each other + and subsets it +
+ + +
+ UNION combines the results of + JOIN can retrieve data from two or +
+ two or more queries into a single+ more tables based on logical relationships +
+ result set that includes all the + between the tables. Joins indicate how SQL +
+ rows that belong to all queries + should use data from one table to select +
+ in the union. + the rows in another table. +
+ + +
+ UNION makes two queries look + JOIN examine two or more tables in +
+ like one. + a single query statement +
+ + +
+ UNION returns the results of two + JOIN relates similar data in different +
+ different queries as a single + tables. +
+ recordset. + +
+ + +
+----------------------------------+--------------------------------------------+
JOIN picks fields from table A and fields from table B and put all of them together, JOIN is "horizontal" for example:
SELECT A.A1, A.A2, A.A3, B.B1, B.B2
FROM A
INNER JOIN B
ON A.A10 = B.B20
which can be written also like:
select A1, A2, A3, B1, B2 from TABLEA, TABLEB
WHERE A10 = B20
result:
Field-A1 | Field-A2 | Field-A3 | Field-B1 | Field-B2 |
...
UNION/UNIONALL:
Difference between the two is that UNION returns only distinct results while UNIONALL returns ALL the results (including duplicates). UNION/UNIONALL combines the results of two selects - but there's a "catch" - the column-names must be exactly the same - this property make UNION "vertical", for example:
Select A1 as X1, A2 as X2 from TABLEA
UNIONALL
Select B1 as X1, B2 as X2 from TABLEB
result:
Field-X1 | Field-X2
A1 | A2
B1 | B2
...
join:
A join is an SQL operation performed to establish a connection between two or more database tables based on matching columns, thereby creating a relationship between the tables. Most complex queries in an SQL database management system involve join commands.
e.g:
SELECT Orders.OrderID, Customers.CustomerName, Orders.OrderDate
FROM Orders
INNER JOIN Customers
ON Orders.CustomerID=Customers.CustomerID;
The UNION operator is used to combine the result-set of two or more SELECT statements.
Notice that each SELECT statement within the UNION must have the same number of columns. The columns must also have similar data types. Also, the columns in each SELECT statement must be in the same order
syntax:
SELECT column_name(s) FROM table1
UNION ALL
SELECT column_name(s) FROM table2;

Append Table Name to Field Name with Select *

Sorry if this is a duplicate. I have searched but only find aliasing fields and tables.
I have a query:
SELECT *
FROM MyTable1 ca LEFT OUTER JOIN MyTable2 dcn ON dcn.dstrct_code = ca.dstrct_code
LEFT OUTER JOIN MyTable2 cdn ON cdn.dstrct_code = ca.cost_dstrct_cde
LEFT OUTER JOIN MyTable3 bb ON bb.supplier_code = ca.supplier_code
WHERE ca.dstrct_code = '0001'
AND ca.req_232_type = 'P'
AND ca.requisition_no = '264982 000'
AND ca.alloc_count = '01'
ORDER BY ca.alloc_count ASC
Please dont shoot me down for using * im not done with the query yet. If I execute this query I get a row of data however the tables I am selecting from all have a good number of fields and many are simularly named. So my question is... Is there anyway to select * from and append the table name to the field name so it is more obvious which field belongs to which table?
I don't think there's a way to do that directly but you can do this instead. Run a query like this:
SELECT
(case t.name when 'MyTable1' then 'ca' when 'MyTable2' then 'dcn' when 'MyTable3' then 'cdn' when 'MyTable4' then 'bb' end)
+ '.' + c.name
+ ' AS "' + t.name + '.' + c.name + '",'
FROM sys.tables AS t
INNER JOIN sys.columns c ON t.OBJECT_ID = c.OBJECT_ID
WHERE t.name in ('MyTable1', 'MyTable2', 'MyTable3', 'MyTable4')
ORDER BY t.name
Run it, preferably with results to Text (Ctrl+T), and use the results instead of the * in your original query. You have to manually remove the comma from the last line.
If you like the approach, you could streamline the process with some dynamic SQL.