How to render an SVG from PostGIS using ST_AsSVG

The Postgis function ST_AsSVG simply converts geometries into their SVG point or path equivalents, and does not allow you to add any attributes/styling directly. For example, a query with a Point, Linestring and Polygon:

WITH shapes (geom, attribute) AS 
   (VALUES(
      (SELECT ST_MakePoint(0,0)),1),
      ((ST_MakeLine(ST_MakePoint(0,0), ST_MakePoint(10,10))), 2), 
      ((SELECT ST_MakeBox2d(ST_MakePoint(0,0), ST_MakePoint(10,10))), 3)
   )
SELECT ST_AsSVG(geom) from shapes;

returns:

 cx="0" cy="0"
 M 0 0 L 10 -10
 M 0 0 L 0 -10 10 -10 10 0 Z

which is a point, an unclosed linestring and a closed line, ie, a polygon. M means move to, L means line to and Z means close. There are other geometry types in SVG, but this is what ST_AsSVG returns (see docs for the Multi version of the same).

By itself, this isn't very helpful, as you are missing the path tags and any styling information, a full example of which would look something like:

 <path d="M 175 200 l 150 0" stroke="green" stroke-width="3" fill="none" />
 <path d="M 100 350 q 150 -300 300 0" stroke="blue" stroke-width="5" fill="none" />

See w3schools SVG Tutorial for more information.

So, if you want to actually create valid SVG using a Postgis query, you will need to add path tags and color, line, fill, etc formatting. This can be accomplished by using the concat operator and a case statement to set the formatting. For example,

WITH shapes (geom, attribute) AS (
  VALUES(
    (SELECT ST_MakeLine(ST_MakePoint(0,0), ST_MakePoint(10,10))), 2),
    ((SELECT ST_Envelope(ST_MakeBox2d(ST_MakePoint(0,0), ST_MakePoint(10,10)))), 3)
  ) 
  SELECT 
      concat(
         '<path d= "', 
         ST_AsSVG(geom,1), '" ', 
         CASE WHEN attribute = 0 THEN 'stroke="red" stroke-width="3" fill="none"' 
         ELSE 'stroke="black" stroke-width="2" fill="green"' END,
         ' />') 
 FROM shapes;

which returns:

<path d= "M 0 0 l 10 -10" stroke="black" stroke-width="2" fill="green" />
<path d= "M 0 0 l 0 -10 10 0 0 10 z" stroke="black" stroke-width="2" fill="green" />

Finally, if you wrap all of that in array_to_string and array_agg, and add the head and footer, ie, the <svg height="400" width="450"> and </svg>, you will end up with one block of SVG representing all your geometries, eg,

WITH shapes (geom, attribute) AS (
  VALUES(
    (SELECT ST_MakeLine(ST_MakePoint(0,0), ST_MakePoint(10,10))), 2),
    ((SELECT ST_Envelope(ST_MakeBox2d(ST_MakePoint(0,0), st_makepoint(10,10)))), 3)
  ),
  paths (svg) as (
     SELECT concat(
         '<path d= "', 
         ST_AsSVG(geom,1), '" ', 
         CASE WHEN attribute = 0 THEN 'stroke="red" stroke-width="3" fill="none"' 
         ELSE 'stroke="black" stroke-width="2" fill="green"' END,
          ' />') 
     FROM shapes
 )
 SELECT concat(
         '<svg height="400" width="450">',
         array_to_string(array_agg(svg),''),
         '</svg>')
 FROM paths;

which now returns the single record:

<svg height="400" width="450"><path d= "M 0 0 l 10 -10" stroke="black" stroke-width="2" fill="green" /><path d= "M 0 0 l 0 -10 10 0 0 10 z" stroke="black" stroke-width="2" fill="green" /></svg>

TL;DR, other options

At which point you are probably thinking, TL;DR, and it is true this is a lot of work, and the case statements to make the stroke color, width, etc, could get very long and unwieldy.

There are other options. Geoserver (with a Postgis/vector data source) supports SVG as an output format and you can use SLDs or CartoCSS within Geoserver to style them up, then just request a WMS with SVG as output format and you are done. As @Scro also said, you can use tools like TileMill to do the styling for you (not tested). So, after a very long answer, I am basically suggesting that you should not use ST_AsSVG directly for anything other than very quick and dirty SVGs.