SQL Size comparison - union

I have a database where I check on the size, because clients may only use a certain amount of space, aswell as they may only have a certain number of 'pages', which I put in the db aswell.
I have the following sql query:
SELECT table_schema "Servers",
sum( data_length + index_length ) / 1024 / 1024 "Data Base Size in MB",
sum( data_free )/ 1024 / 1024 "Free Space in MB"
FROM information_schema.TABLES
GROUP BY table_schema ;
This returns a table with the information I need. However, I would like to add 3 coloumns that also show how much each user is using. First I tried like this:
SELECT table_schema "Servers",
sum( data_length + index_length ) / 1024 / 1024 "Data Base Size in MB",
sum( data_free )/ 1024 / 1024 "Free Space in MB",
property_value "MaxWebhotelSize"
FROM information_schema.TABLES, properties
WHERE property_key LIKE 'MaxWEbhotelSize'
GROUP BY table_schema
UNION
SELECT property_value "MaxPages"
FROM properties
WHERE property_key LIKE 'MaxPages';
This should take add two of the coloumns that I need. If I leave out everything from union and down it works well and adds information about maximum webhotel size to the table, but when I try to add another coloumn I get an error saying "The used SELECT statements have a different number of columns". I tried some other ways around it, but can't seem to figure out a good way where I get the right results. I'm quite new to SQL, sorry if this is a stupid question.

In a union query, the number of columns should be equal.
So, if you have 3 columns in the first section of your union query, you should also have 3 columns in the second.
In your example, you only have 1 column in the second section. Please specify what you require in the additional 2 columns, and we might be able to assist with the query.

Related

Performance of PIVOT and MERGE - is there a better way I can do this?

Sorry, this might be a bit out of scope for the community here, but I wanted to get a second opinion.
I have a table with the following structure
Table_1
TYPE ITEM DATE QTYA QTYB QTYC
X AAA 17/08/2015 100 200 300
X AAA 18/08/2015 100 170 240
Y BBB 17/08/2015 100 240 100
I need to use this table as a source for a merge, but the target table is formatted completely differently
Table_2
ITEM QTYA_1 QTYA_2......QTYA_31 QTYB_1 QTYB_2 QTYB_3......QTYB_31 QTYC_1 QTYC_2....QTYC_31
(the numbers suffixed at basically the day of the month)
I can convert Table 1 to the format of Table 2 using a mix of UNION ALL and PIVOT, but the performance isn't that good - particularly since I have to save the information in a temp table first before merging it in (Each 'type' in Table_1 has a different start date and I cannot overwrite previous values in Table_2 starting from a different date - basically I have to merge the table 3 or 4 times with a different item type and different start date)
Here's what I got so far
SELECT TOP 0 * INTO #TEMP_PIVOT_TABLE
INSERT INTO #TEMP_PIVOT_TABLE SELECT * FROM
(SELECT ITEM, 'QTYA_' + CONVERT(DATETIMEFROMPARTS(day,DATE) AS VARCHAR) as 'Quantity Type', QTY_A FROM TABLE_1
UNION_ALL
SELECT ITEM, 'QTYB_' + CONVERT(DATETIMEFROMPARTS(day,DATE) AS VARCHAR) as 'Quantity Type', QTY_B FROM TABLE_1
UNION_ALL
SELECT ITEM, 'QTYC_' + CONVERT(DATETIMEFROMPARTS(day,DATE) AS VARCHAR) as 'Quantity Type', QTY_C FROM TABLE_1
) A
PIVOT
(SUM(QUANTITY) FOR QUANTITY_TYPE IN ([QTYA_1], [QTYA_2],.....[QTYA_31],[QTYB_1].....[QTYC_31],[QTYC_1].....[QTYC_31])) AS B
----For each different date per item_type, construct a string only selecting those days in the month.
Then merge the results from #TEMP_PIVOT_TABLE into TABLE_2 for each Item TYPE` with dynamic SQL
1) Is there any better way to do the PIVOT command? The performance of the UNION ALL commands isn't encouraging - particularly since the table I'm reading from has large amounts of data. I'm also simplifying here for the sake of brevity - the actual table needs to map 5 columns or so, each with 31 days
2) Is there a better way to do the MERGE? I dislike using a loop + Dynamic SQL to basically read the same dataset repeatedly just so to merge on different columns, but I can't see a different way. That and building the MERGE command dynamically with so many columns will make it troublesome for future maintenance.
Does anyone have an idea how I can go about this more efficiently?
You can replace the union all internal query with the following query. This query needs only one table hit instead of hitting table for each column.
To unpivot the data use cross apply with table valued constructor
select ITEM,[Quantity Type],QTY
from yourtable
cross apply
(
values
('QTYA_' + CONVERT(DATEPART(day,DATE) AS VARCHAR),QTY_A),
('QTYB_' + CONVERT(DATEPART(day,DATE) AS VARCHAR),QTY_B),
('QTYC_' + CONVERT(DATEPART(day,DATE) AS VARCHAR),QTY_C),
)
CS ([Quantity Type],QTY)

How to SELECT LIMIT in ASE 12.5? LIMIT 10, 10 gives syntax error?

How can I LIMIT the result returned by a query in Adaptive Server IQ/12.5.0/0306?
The following gives me a generic error near LIMIT:
SELECT * FROM mytable LIMIT 10, 10;
Any idea why? This is my first time with this dbms
Sybase IQ uses row_count to limit the number of rows returned.
You will have to set the row count at the beginning of your statement and decide whether the statement should be TEMPORARY or not.
ROW_COUNT
SET options
LIMIT statement is not supported in Sybase IQ 12. I think there is not simple or clean solution, similarly like in old SQL server. But there are some approches that works for SQL server 2000 and should work also for Sybase IQ 12. I don't promise that queries below will work on copy&paste.
Subquery
SELECT TOP 10 *
FROM mytable
WHERE Id NOT IN (
SELECT TOP 10 Id FROM mytable ORDER BY OrderingColumn
)
ORDER BY OrderingColumn
Basically, it fetches 10 rows but also skips first 10 rows. To get this works, rows must be unique and ordering is important. Id cannot be more times in results. Otherwise you can filter out valid rows.
Asc-Desc
Another workaround depends on ordering. It uses ordering and fetches 10 rows for second page and you have to take care of last page (it does not work properly with simple formula page * rows per page).
SELECT *
FROM
(
SELECT TOP 10 *
FROM
(
SELECT TOP 20 * -- (page * rows per page)
FROM mytable
ORDER BY Id
) AS t1
ORDER BY Id DESC
) AS t2
ORDER BY Id ASC
I've found some info about non working subqueries in FROM statement in ASE 12. This approach maybe is not possible.
Basic iteration
In this scenario you can just iterate through rows. Let's assume id of tenth row is 15. Then it will select next 10 rows after tenth row. Bad things happen when you will order by another column than Id. It is not possible.
SELECT TOP 10 *
FROM mytable
WHERE Id > 15
ORDER BY Id
Here is article about another workarounds in SQL server 2000. Some should also works in similar ways in Sybase IQ 12.
http://www.codeproject.com/Articles/6936/Paging-of-Large-Resultsets-in-ASP-NET
All those things are workarounds. If you can try to migrate on newer version.

How to Select row range wise in SQL Server

I Have a very large database in SQL Server ( around 20 Million Rows ). I have to take backup of that database in .csv format. But .csv supports only 1 million rows in a single file. So I am not able to take backup of whole database. So I have to break that database in 20 Parts.
For that I have to select 1-1 Million then 1 million to 2 million and so on.
So for this I can take 1st 1 million by using select TOP query.But I am not able to retrieve 1 Million to 2 million and so on....
So Please help me to do so. What tricks I should use or what should I do to take backup in .csv files.
try the following
select tab.col1,tab.col2,..tab.coln
from (
select a.*.row_number() over(order by Id) as rn
from table as a) as tab
where tab.rn between limit1 and limit 2
order by id
Use the LIMIT clause:
http://dev.mysql.com/doc/refman/5.0/en/select.html
Ie:
/* rows 0-1 million */
SELECT * FROM tbl LIMIT 0,1000000;
/* rows 1-2 million */
SELECT * FROM tbl LIMIT 1000000,1000000;
/* etc (these might be off by 1) */

SQL: SELECT n% with pictures, (100-n)% without pictures

we have a DB which stores users who may have pictures.
I am looking for an elegant way in SQL to get the following results:
Select n users. Of those n users e.g. 60% should have an associated picture and 40% should not have a picture. If there are less than 60% users having a picture the result should be filled up with users wihtout an image.
Is there some elegant way in SQL without firing multiple SELECTs to the DB?
Thank you very much.
So you provide #n, being the number of users you want.
You provide #x being the percentage of those users who should have pictures.
select top (#n) *
from
(
select top (#n * #x / 100) *
from users
where picture is not null
union all
select top (#n) *
from users
where picture is null
) u
order by case when picture is not null then 1 else 2 end;
So... you want at most #n * #x / 100 users who have pictures, and the rest have to be people who don't have pictures. So I'm doing a 'union all' between my #n*#x/100 picture-people and enough others to complete my #n. Then I'm selecting them back, ordering my TOP to make sure that I keep the people who have a picture.
Rob
Edited: Actually, this would be better:
select top (#n) *
from
(
select top (#n * #x / 100) *, 0 as NoPicture
from users
where picture is not null
union all
select top (#n) *, 1 as NoPicture
from users
where picture is null
) u
order by NoPicture;
...because it removes the impact of the ORDER BY.
Ugly code:
SELECT TOP #n * FROM
(
//-- We start selecting users who have a picture (ordered by HasPicture)
//-- If there is no more users with a picture, this query will fill the
//-- remaining rows with users without a picture
SELECT TOP 60 PERCENT * FROM tbUser
ORDER BY HasPicture DESC
UNION
//-- This is to make sure that we select at least 40% users without a picture
//-- AT LEAST because in the first query it is possible that users without a
//-- picture have been selected
SELECT TOP 40 PERCENT * FROM tblUser
WHERE HasPicture = 0
//-- We need to avoid duplicates because in the first select query we haven't
//-- specified HasPicture = 1 (and we didn't want to).
AND UserID not IN
(
SELECT TOP 60 PERCENT UserID FROM tbUser
ORDER BY HavePicture DESC
)
)
SELECT TOP(n) HasPicture --should be 0 or 1 to allow ORDER
FROM Users
ORDER BY 1
Use the Select case for this type of Requirement.

Use of SET ROWCOUNT in SQL Server - Limiting result set

I have a sql statement that consists of multiple SELECT statements. I want to limit the total number of rows coming back to let's say 1000 rows. I thought that using the SET ROWCOUNT 1000 directive would do this...but it does not. For example:
SET ROWCOUNT 1000
select orderId from TableA
select name from TableB
My initial thought was that SET ROWCOUNT would apply to the entire batch, not the individual statements within it. The behavior I'm seeing is it will limit the first select to 1000 and then the second one to 1000 for a total of 2000 rows returned. Is there any way to have the 1000 limit applied to the batch as a whole?
Not in one statement. You're going to have to subtract ##ROWCOUNT from the total rows you want after each statement, and use a variable (say, "#RowsLeft") to store the remaining rows you want. You can then SELECT TOP #RowsLeft from each individual query...
And how would you ever see any records from the second query if the first always returns more than 1000 if you were able to do this in a batch?
If the queries are simliar enough you could try to do this through a union and use the rowcount on that as it would only be one query at that point. If the queries are differnt in the columns returned I'm not sure what you would get by limiting the entire group to 1000 rows because the meanings would be different. From a user perspective I'd rather consistently get 500 orders and 500 customer names than 998 orers and 2 names one day and 210 orders and 790 names the next. It would be impossible to use the application especially if you happened to be most interested in the information in the second query.
Use TOP not ROWCOUNT
http://msdn.microsoft.com/en-us/library/ms189463.aspx
You trying to get 1000 rows MAX from all tables right?
I think other methods may fill up with from the top queries first, and you may never get results from the lower ones.
The requirement sounds odd. Unless you are unioning or joining the data from the two selects, to consider them as one so that you apply a max rows simply does not make sense, since they are unrelated queries at that point. If you really need to do this, try:
select top 1000 from (
select orderId, null as name, 'TableA' as Source from TableA
union all
select null as orderID, name, 'TableB' as Source from TableB
) a order by Source
SET ROWCOUNT applies to each individual query. In your given example, it's applied twice, once to each SELECT statement, since each statement is its own batch (they're not grouped or unioned or anything, and so execute completely separately).
#RedFilter's approach seems the most likely to give you what you want.
Untested and doesn't make use of ROWCOUNT, but could give you an idea?
Assumes col1 in TableA and TableB are the same type.
SELECT TOP 1000 *
FROM (select orderId
from TableA
UNION ALL
select name from TableB) t
The following worked for me:
CREATE PROCEDURE selectTopN
(
#numberOfRecords int
)
AS
SELECT TOP (#numberOfRecords) * FROM Customers
GO
this is your solution :
TOP (Transact-SQL)
and about ##RowCount you can read this Link :
SET ROWCOUNT (Transact-SQL)
Important
Using SET ROWCOUNT will not affect DELETE, INSERT, and UPDATE statements in a future release of SQL Server. Avoid using SET ROWCOUNT with DELETE, INSERT, and UPDATE statements in new development work, and plan to modify applications that currently use it. For a similar behavior, use the TOP syntax. For more information, see TOP (Transact-SQL).
I think two way will work.!

Resources