How to do count(*) for specific alias in SQL server? - sql-server

I have an SQL command with multiple tables added with LEFT JOIN table1 AS alias. I want to count all rows in table1, but not table2.
In a command where there's only one table, I can just do count(*). Here, however, * refers to all the rows in all the conjoined tables. table1.* gets all the rows from just that table, but count(table1.*) throws an Incorrect syntax near '*'. error.
Is this a syntax problem, or something deeper? How do I get the desired functionality?
Running Microsoft SQL Azure (RTM) - 12.0.2000.8

Instead of query like this
select *,count(C.CustomerID) over (partition by U.UserID)
from Users U
left join Customers C on C.ManagerID = U.UserID
where U.UserID between 1574 and 1580
You can use query like this
select *
from Users U
outer apply (
select Cnt = count(*) from Customers
where ManagerID = U.UserID ) res
where U.UserID between 1574 and 1580

Related

Convert CROSS APPLY in DB2 database

I am trying to convert the below MSSQL query into DB2 query.
But i am facing issues . I got to know "CROSS APPLY" doesnt exist for DB2
SQL Server query:
SELECT DISTINCT p.ID,
p.COMPANY,
p.NAME,
format(d.startTime, 'yyyy-MM-dd HH:mm:ss.fff')
FROM PROCESS p
CROSS APPLY (SELECT MAX(END_TIME) AS startTime FROM PROCESS WHERE ID = (SELECT MAX(ID) FROM PROCESS)) AS d
WHERE p.ID = (SELECT MAX(ID) FROM PROCESS)
Error:
Error: com.ibm.db2.jcc.c.SqlException: DB2 SQL error: SQLCODE: -104, SQLSTATE: 42601, SQLERRMC: APPLY;N process
CROSS;JOIN
How the above query can be converted into DB2 query format?
The SQL Server manual says that a CROSS APPLY is used with table functions.
https://learn.microsoft.com/en-us/sql/t-sql/queries/from-transact-sql?view=sql-server-ver15#using-apply
That the right_table_source can use a table-valued function that takes a column from the left_table_source as one of the arguments of the function.
Your example does not use any, so I assume it is simply the equivalent to a CROSS JOIN in Db2.
By the way, this statement would likely get the same result (assuming COMPANY and NAME are the same for a given ID)
SELECT
ID
, COMPANY
, NAME
, format(END_TIME, 'yyyy-MM-dd HH:mm:ss.fff')
FROM
( SELECT *
, ROW_NUMBER() OVER(ORDER BY ID DESC, END_TIME DESC) AS RN
FROM
PROCESS p
)
WHERE
RN = 1
This might or might not be more optimal at execution time
The DB2 equivalent is the terribly named TABLE operator. The name makes it very challenging to find documentation.
See if this works for your query.
SELECT DISTINCT p.ID,
p.COMPANY,
p.NAME
FROM PROCESS p
JOIN TABLE (
SELECT ID
,MAX(END_TIME) AS startTime
FROM PROCESS
WHERE ID = (
SELECT MAX(ID)
FROM PROCESS
)
GROUP BY ID
) AS D
ON P.ID = D.ID
However, I've found CTEs in DB2 to be very effective. In SQL Server, a CTE is almost like a layer applied to a query, similar to a view. The expressions in the CTE are generally combined with the underlying statements and executed as a single statement.
I'm not a DB2 expert, but it seems to me that a CTE is materialized to an internal table and the result is combined with the remaining statements.
With the same query, data and indexes, DB2 and SQL Server can have very different performance when CTEs are involved.

Selecting count of exist rows in other table and join it to our SQL server table

I have two tables in SQL server. first one is table of customers info and second includes all purchases,
At first Table i have id of our customers, and the purchases table although has the id of who bought that product. so how can i select all customers table that include how many time they purchased products?
i tried this
SELECT TOP 2000 COUNT(tblpurchase.id) as id2,tblcustomers.* From tblpurchase
right join on tblpurchase.id=tblcustomers.id
but didn't word. how can i solve this?
Use OUTER APPLY
SELECT TOP 2000 tblcustomers.* ,M.CustomerCount
From tblcustomers
OUTER APPLY(
SELECT COUNT(*) as CustomerCount
from tblpurchase
WHERE tblpurchase.CustomerIDColumn = tblcustomers.id
)M
Here tblpurchase.CustomerIDColumn use actual name of customerID column
Also you can with LEFT JOIN
SELECT TOP 2000
C.*,
P.CustomerCount
From
tblcustomers C LEFT JOIN
(
SELECT
TP.CustomerId,
COUNT(*) as CustomerCount
FROM
tblpurchase TP
GROUP BY
TP.CustomerId
) P ON C.Id = P.CustomerId

rank() equivalent for SQL Server 2000

I am using SQL Server 2000 so sadly common table expressions are out but I have the following 2 table structure:
Invoices
id
InvoiceQueryReasons
id
invoice_id
reason
date_queried
I want to inner join from Invoices to InvoiceQueryReasons and only get 1 row for each invoice that selects the most recent InvoiceQueryReasons record.
If I was using a CTE with postgress I would do something like:
SELECT *
FROM
(SELECT
"i"."id", "iq"."reason", "iq"."date_queried",
rank() OVER (PARTITION BY "invoice_id" ORDER BY "date_queried" DESC) AS "invoice_query_rnk",
FROM "invoices" i
INNER JOIN "InvoiceQueryReasons" iq ON ("i"."id" = "iq"."invoice_id")
) AS "iqrs"
INNER JOIN
"invoices" ON ("iqrs"."id" = "invoices"."id")
WHERE
("invoice_query_rnk" = 1)
Apologies if the query is not exactly right, I am writing this on a non-dev machine.
How could I write a similar query in SQL Server 2000 where I do not have common table expression?
This is the way I always used to do this in SQL Server 2000:
FROM Table1
INNER JOIN Table2 ON Table2.PrimaryKey=(
SELECT TOP 1 t2.PrimaryKey
FROM Table2 t2
WHERE t2.ForeignKey=Table1.PrimaryKey
ORDER BY t2 DateColumn DESC
)

Cross querys with CTE into single query (MSSQL)

Good afternoon,
I've 2 tables into my SQL DB, in the first I've the asignation for days to a person, and other the registry per day of this person, I will like see if this person have or not registry for each day into the range of specification.
I've encountered a query that uses CTE for return the range in days independent, and other query in that I've the registry group by person and day, but I can't cross these queries.
Bottom there is a picture with queries and results of each.
Thanks.
My SQL querys
You may use several CTEs in one statement, so you may put each query in separate CTE and join them later lake that:
SELECT
p.cedula, p.starttime,
r.Descr, r.Candidad
FROM ctePeriod p
LEFT JOIN cteRegistry r on r.cedula = p.cedula AND r.Dia = p.StartTime
ORDER BY p.cedula, p.starttime
all above as a single query.
Another way is to put results of your Query1 and Query2 into temp tables and build your final query on those temp tables e.g.:
SELECT DISTINCT ...
INTO #Period
FROM CTE
WHERE ...
SELECT ...
INTO #Registro
FROM Registro
GROUP BY ...
SELECT
p.cedula, p.starttime,
r.Descr, r.Candidad
FROM #Period p
LEFT JOIN #Registro r on r.cedula = p.cedula AND r.Dia = p.StartTime
ORDER BY p.cedula, p.starttime

How to optimize view performance in SQL Server 2012 by indexing

I have a view like that:
create view dbo.VEmployeeSalesOrders
as
select
employees.employeeID, Products.productID,
Sum(Price * Quantity) as Total,
salesDate,
COUNT_BIG() as [RecordCount]
from
dbo.Employees
inner join
dbo.sales on employees.employeeID = sales.employeeID
inner join
dbo.products on sales.productID = products.ProductID
group by
Employees.employeeID, products.ProductID, salesDate
When I select * from dbo.VEmployeeSalesOrders it takes 97% of the execution plan. It needs it to be faster.
And when I try to create an index, an exception fires with the following message:
select list doesn't include a proper use on count_Big()
Why am getting this error?
1-first you need to alter your view and make it contains COUNT_BIG() function because you used aggregate function in select statment,
AND THE REASON FOR USING THAT is that SQL Server needs to track the record where the record is ,number of records
like this
create view dbo.VEmployeeSalesOrders
as
select employees.employeeID,Products.productID,Sum(Price*Quantity)
as Total,salesDate,COUNT_BIG(*) as [RecordCount]
from dbo.Employees
inner join dbo.sales on employees.employeeID=sales.employeeID
inner join dbo.products on sales.productID-products.ProductID
group by Employees.employeeID,products.ProductID,salesDate
2- then you need to create index like that
Create Unique Clustered Index Cidx_IndexName
on dbo.VEmployeeSalesOrders(employedID,ProductID,SalesDate)
Hope It Works

Resources